共享同名属性的三个接口如何实现自定义typeguard匹配对应setValue类型
问题原因
你当前遇到的类型不匹配问题,本质是TypeScript无法关联解构后两个独立变量的类型关系:你通过分布式条件类型生成的Props是联合类型,每个联合分支的value和setValue是一一对应的,但将两个属性单独解构出来后,TS无法识别value的收窄结果和setValue的关联,导致setValue始终是全量交叉类型。
解决方法1:不解构props,直接引用对象属性
TypeScript支持对联合类型的对象属性做联动收窄,只要你不拆分对象,判断props.value的类型后,props.setValue的类型会自动匹配当前分支的对应类型:
const handleChange = (data: string) => { if (isAnimal(props.value)) { props.setValue({ ...props.value, type: data }); } else if (isCat(props.value)) { props.setValue({ ...props.value, type: data }); } else if (isBus(props.value)) { props.setValue({ ...props.value, type: data }); } };
这种改法成本最低,不需要调整原有类型定义和type guard逻辑。
解决方法2:改写为泛型组件(更适合当前场景)
你的需求里三个接口都携带type字段,且修改逻辑完全一致,直接把组件改写为泛型可以完全避免类型收窄的工作:
import React from 'react'; interface Animal { type: string; age: number; } interface Cat extends Animal { typeOfCat: string; } interface Bus { type: string; model: string; } type MergeTypes = Animal | Cat | Bus; // 泛型约束T必须是三个接口的联合类型 const ChangeType = <T extends MergeTypes>(props: { value: T; setValue: React.Dispatch<React.SetStateAction<T>>; }): JSX.Element => { const { value, setValue } = props; const handleChange = (data: string) => { // 不需要任何类型判断,TS可自动识别类型合法 setValue({ ...value, type: data }); }; return ( <form> <label> <input type="text" value={value.type} onChange={(e) => handleChange(e.target.value)} /> </label> </form> ); }; // 调用时类型校验完全正常 const jsx = <ChangeType value={{ type: 'animal', age: 42 }} setValue={() => { }}/>; const jsx2 = <ChangeType value={{ type: 'animal', age: 42, typeOfCat: 'cat' }} setValue={() => { }}/>; const jsx3 = <ChangeType value={{ type: 'vehicle', model: 'volksvagen' }} setValue={() => { }}/>;
这种方案性能和可维护性更高,适合你的业务场景。
内容的提问来源于stack exchange,提问作者Jueltrae
相关产品推荐
相关产品推荐

