我正在尝试创建一个React HoC来设置一些道具(如果没有提供的话)。
我可以根据需要提供该代码,但是它带有一些React包,这些代码使代码变得复杂,并且实际上与我遇到的错误没有任何关系。
因此,我创建了一个MVCE,可以更清晰地重现该问题:
props
name
是不可变的,因此如果它以undefined
的形式出现在if (props.name == null) {
props.name = "alice";
}
中,那么我将无法做到:
...rest
我得到了错误:
TypeError: Cannot add property XXX, object is not extensible
因此,我改为使用object destructuring来获取我知道应该存在的字段,并将其余字段放在newProps
中。
然后,我构造...rest
并将我默认的字段与{ name: string; } & Pick<TProps, Exclude<keyof TProps, "name">>
结合起来。
问题在于,此时我得到了错误:
类型
TProps
不可分配给类型name
。
对我来说,这是“ TProps,不包括name属性以及name字段,不能分配给TProps”,这让我有些困惑。
我想知道是否不喜欢string
现在是string?
而不是string
。问题是没有道理的,因为string?
可分配给const newProps: TProps = {
name: ((nameProp != null) ? nameProp : "Alice") as string | undefined,
...rest
};
,但是我还是尝试修改代码。
{ name: string; }
但是,正如预期的那样,没什么区别。
我注意到错误消息中指出类型是{ name?: string; }
而不是const newRequiredProps: { name?: string } = {
name: (nameProp != null) ? nameProp : "Alice"
};
const newProps: TProps = {
...newRequiredProps,
...rest
};
,所以我进行了代码更改以尝试解决该问题。
{ name?: string; } & Pick<TProps, Exclude<keyof TProps, "name">>
现在,错误消息显示了“更正确”的类型,但基本上保持不变。
类型
TProps
不可分配给类型as
。
我确实发现了一件可行的事情,那就是使用const newProps: TProps = {
name: (nameProp != null) ? nameProp : "Alice",
...rest
} as TProps;
强制类型:
{{1}}
但是那感觉就像是我只是在掩盖打字问题,而没有真正解决它。
有没有办法让类型系统理解我要做什么,而不是强迫它接受类型?
答案 0 :(得分:1)
对于编译器来说,很难验证对泛型类型的复杂条件类型操纵。只要您确定不会发生任何疯狂的事情,那么您正在执行的类型断言是完全可以接受的:
type PossiblyBob = { name?: "Bob" };
const possiblyBob: PossiblyBob = Math.random() < 0.5 ? {} : { name: "Bob" };
setDefaults(possiblyBob);
请注意,类型PossiblyBob
具有name
属性,该属性必须是字符串"Bob"
或undefined
。当您调用setDefaults(possiblyBob)
时,它会将TProps
实例化为PossiblyBob
。但是在您的setDefaults()
实现中,newProps
在运行时有50%的机会成为{name: "Alice"}
,这不是PossiblyBob
。哦,很好。
但是,假设不会发生这种极端情况,您可以告诉编译器不要担心,并使用类型断言。
说不需要类型声明的同一件事的一种可能更简短的方法是使用Object.assign()
:
const setDefaults: TProps = <TProps extends RequiredProps>(props: TProps) => {
const newProps = Object.assign({ name: "Alice" }, props);
};
这差不多是同一件事(只要props.name
实际上没有设置为值undefined
)。但是,缺少类型错误是一种技巧。 Object.assign()
的{{3}}返回其输入类型的standard library typings,即intersection。最终,它们可能会not technically true的返回类型Object.assign()
,然后您在那里也会遇到相同的类型断言问题。
所以我想我的建议是离开类型断言并继续。
希望有所帮助;祝你好运!