TypeScript如何正确设置组件联合类型解决TS2322报错
报错原因
这个报错不是TypeScript把联合类型识别成了交叉类型,而是函数参数的逆变校验规则导致的正常类型安全提示:
你定义的数组项类型要求elm函数必须能接收ElementList联合类型的所有可能值(也就是不管传入Thing1Props还是Thing2Props,函数都要能正常处理)。但你传入的第一个elm函数仅能接收Thing1Props,传入Thing2Props时会缺少one/two字段,完全不满足入参要求;第二个elm仅能接收Thing2Props,同理也不满足约束,因此TS抛出类型错误。
你之所以会误以为TS把联合类型识别成了交叉类型,是因为函数参数位置的联合类型会在赋值校验时表现出类似交叉的约束特性,本质是类型安全的必要设计,不是识别错误。
修复方案
推荐使用可辨识联合+分布式条件类型实现name和组件props的强绑定,从根源保证类型安全:
const Thing1 = (props: Thing1Props) => <div>Thing 1</div> const Thing2 = (props: Thing2Props) => <div>Thing 2</div> type Thing1Props = { type: 'thing1'; one: string; two: string; } type Thing2Props = { type: 'thing2'; three: string; four: string; } export type ElementList = Thing1Props | Thing2Props; // 用分布式条件类型生成配置项的联合类型,保证name和elm的入参类型一一对应 type ElementConfig = ElementList extends infer T ? T extends ElementList ? { name: T['type']; elm: (props: T) => JSX.Element } : never : never; const elementList: ElementConfig[] = [ { name: 'thing1', elm: (props: Thing1Props) => <Thing1 {...props} /> }, { name: 'thing2', elm: (props: Thing2Props) => <Thing2 {...props} /> }, ];
后续调用组件时,只要通过type字段做辨识,TS就能自动推导出对应组件需要的props类型,不会出现类型不匹配问题。
如果不需要强类型的动态查找能力,也可以用更简单的as const写法让TS自动推导数组的精确类型,省去手动写类型的成本:
const elementList = [ { name: 'thing1', elm: (props: Thing1Props) => <Thing1 {...props} /> }, { name: 'thing2', elm: (props: Thing2Props) => <Thing2 {...props} /> }, ] as const;
这种写法的缺点是后续根据name动态匹配组件时,需要额外写类型提取逻辑才能拿到正确的props类型推导。
注意:不要直接用
any等类型断言绕开校验,否则会失去TS的类型保护,后续传错props不会有任何提示。
内容的提问来源于stack exchange,提问作者Matt Coady
相关产品推荐
相关产品推荐

