我想编写一个接收defaultValue
参数类型string | number
的反应输入组件。此组件具有状态类型,表示为defaultValue
类型;
这是我的代码:
type TypeName<T> = T extends number ? "number" : "string";
interface IInputProps<P extends string | number>{
defaultValue: P,
rule: (value: P)=>boolean,
onChange: (value: P)=>void
}
interface IInputState<P extends string | number>{
value: P,
type: TypeName<P>
}
class Input<P extends string | number> extends Component<IInputProps<P>,IInputState<P>>{
constructor(props:IInputProps<P>){
super(props);
this.state = {
type: typeof props.defaultValue,
value: this.props.defaultValue
}
在构造函数中有错误
ERROR in [at-loader] ./src/components/Input/index.tsx:21:4
TS2322: Type '"string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"' is not assignable to type 'TypeName<P>'.
Type '"string"' is not assignable to type 'TypeName<P>'.
我该怎么办才能解决问题?
答案 0 :(得分:0)
在这种情况下,您比编译器更聪明。尽管您您知道无论P
是什么,值typeof props.defaultValue
的类型都是TypeName<P>
,但编译器无法弄清楚。它仅意识到typeof props.defaultValue
可以是typeof
运算符产生的字符串值之一:"string"
或"number"
或"boolean"
,等等。甚至如果它意识到它只能是"string"
或"number"
,则不足以使该值正确地与P
相关联以使其成为TypeName<P>
(至少从TypeScript 3.2开始)。
处理此问题的最直接方法就是接受您比编译器更聪明,并assert可以typeof props.defaultValue
对待as
类型{{ 1}}。应编译以下内容:
TypeName<P>
我认为目前没有任何方法可以引导编译器执行这些步骤,以便编译器可以验证this.state = {
type: typeof props.defaultValue as TypeName<P>, // assertion
value: this.props.defaultValue
}
本身,因此您所做的任何事情(例如制作type guard)都将等同于断言。
如果您发现自己经常需要执行此断言,则可以将其抽象为一个函数:
TypeName<P>
这将至少将断言限制在一个地方,并向function getTypeName<T extends string | number>(t: T): TypeName<T> {
return typeof t as TypeName<T>; // assertion
}
的后续用户隐藏问题:
getTypeName()
希望有帮助。祝你好运!