TypeScript开发React组件时判别联合类型props类型收窄失效问题
你遇到的类型推导失败问题,核心是两个错误用法:
- 判别联合类型的判别属性用法不规范:要让TS正确识别联合类型的分支,两个分支的共有判别属性必须是可区分的互斥类型,你给无context分支的context属性设为
never属于错误用法,never类型表示不存在的值的类型,无法参与正常的条件判断,TS不会将其作为合法的判别分支。 - 条件判断逻辑不符合类型收窄规则:使用
props.context !== null进行判断时,TS无法同时将整个props对象收窄到带context的分支,因为never !== null的类型推导结果是never,TS会认为该分支对无context的情况永远不成立,因此不会同步收窄name属性的类型。
正确实现方案
第一步:修正联合类型定义
将无context分支的context属性类型改为可选的undefined,作为合法的判别标志:
interface IValidationRule { id: string; } interface IValidation { [key: string]: IValidationRule[]; } class MyCustomClass { validation: IValidation; } interface IBaseProps { label: string; } interface IWithContext<T> extends IBaseProps { context: T; name: keyof T; } interface IWithoutContext extends IBaseProps { context?: undefined; // 这里修改为可选undefined,作为互斥判别标识 name: string; validation: IValidation; } type IProps<T> = IWithContext<T> | IWithoutContext;
第二步:使用正确的类型收窄逻辑
直接判断props.context是否为真值即可触发正确的类型收窄:
const TestComp = <T extends MyCustomClass>(props: IProps<T>) => { const testMethod = () => { // 注意原代码此处类型标注有误,validation实际类型应为IValidationRule[] let validation: IValidationRule[] = null; if (props.context) { // 此时TS会自动将props收窄为IWithContext<T>类型,name自动推导为keyof T validation = props.context.validation[props.name]; } else { // 此时props收窄为IWithoutContext类型,可直接取validation属性 validation = props.validation; } } return <p>Hello World</p> }
兼容复杂场景的可选方案
如果业务场景判断逻辑更复杂,可以自定义类型守卫来保证收窄稳定性,和你提到的hasProperty方案逻辑一致:
function isWithContext<T>(props: IProps<T>): props is IWithContext<T> { return 'context' in props && props.context != null; } // 使用时直接调用守卫函数即可 if (isWithContext(props)) { validation = props.context.validation[props.name]; }
内容的提问来源于stack exchange,提问作者Jolly
相关产品推荐
相关产品推荐

