打字稿泛型限制数|串

时间:2018-12-12 06:32:49

标签: typescript

我想编写一个接收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>'.

我该怎么办才能解决问题?

1 个答案:

答案 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()

希望有帮助。祝你好运!

相关问题