我正在用ReactJS + Typescript编写一个Web应用程序。我有一个如下定义的功能组件。
我的问题如下:在道具中,对于属性exercise
,父组件正在传递一个对象,该对象要么初始化为空,要么为我指定的某种类型,{{1 }}。然后Typescript引发以下错误:
Exercise
[ts] Property 'description' does not exist on type '{} | Exercise'
如何重构它,以便如果对象确实为空,它将使用默认值,否则,使用传递的值?
编辑:添加了我使用的其他道具
[ts] Property 'title' does not exist on type '{} | Exercise'
答案 0 :(得分:1)
我认为类似的事情应该起作用
type Exercise = {
description: string
id: string
muscles: string
title: string
}
type Props = {
exercise: Partial<Exercise>
}
const Exercises = (props: Props) => {
const exercice = {
description:'Please select an exercise',
title: 'Welcome!',
...props.exercise
}
return (
<Grid container>
<Grid item sm>
<Paper>
<Typography variant="h4">{exercice.title}</Typography>
<Typography variant="subtitle1">{exercice.description}</Typography>
</Paper>
</Grid>
</Grid>
)
}
编辑:对齐代码
答案 1 :(得分:1)
所以总的来说,我认为您的API设计不适用于此组件。您基本上是在将运动实体误用为某些默认的“欢迎消息”,这很容易导致该组件的使用者使用。
我要做的是在没有锻炼的情况下提供这些介绍性默认值,但是绝对不会使用运动道具来分配这些默认值。
接下来,不要使用{}
,它不是空对象(您可以像在https://github.com/Hotell/rex-tils/blob/master/src/guards/types.ts#L39之后那样定义空对象)。在TS 3.0之前,它曾经是底部类型(现在unknown
是底部类型)。这是什么意思? {}
可以是除null / undefined以外的任何值:
// all of this is valid !
let foo: {} = 1231
foo = true
foo = { baz: 'bar' }
foo = [1,2,3]
如果您真的想支持将“空”非原始数据类型传递给组件,请使用null
:
type Props = {
category: string
children?: never
// Maybe type
exercise: null | Exercise
exercises: [string, Exercise[]][]
onSelect: (id: string) => void
}
无论如何,如果您真的想保持API原样。您有以下选择:
const defaultExercise = {
description: 'Please select an exercise',
title: 'Welcome!',
} as Exercise
const Exercises = ({ exercises, category, onSelect, exercise }: Props) => {
// $ExpectType Exercise
const { title, description } = exercise ? exercise : defaultExercise
return <>your markup</>
}
现在,尽管这样做有效,但给您错误的假设。由于您的exercise
可能是不完整的(如果使用默认值),可能会导致运行时错误。您将需要通过警卫(如果是三元的话)来进一步缩小类型。
您可以通过一些类型映射在类型级别上改善这种情况:
// $ExpectType { description: string, title: string, id?: string, muscles?: string }
const defaultExercise = {
description: 'Please select an exercise',
title: 'Welcome!',
} as Partial<Exercise> & Required<Pick<Exercise, 'description' | 'title'>>
如果您在组件中使用id
或muscles
,则使用该类型,您将获得正确的类型,因为它们可能是未定义的,从而正确地反映了我们的三元组
const {
title, //$ExpectType string
description, //$ExpectType string
id, //$ExpectType string | undefined
} = exercise ? exercise : defaultExercise