You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript开发React组件时判别联合类型props类型收窄失效问题

你遇到的类型推导失败问题,核心是两个错误用法:

  1. 判别联合类型的判别属性用法不规范:要让TS正确识别联合类型的分支,两个分支的共有判别属性必须是可区分的互斥类型,你给无context分支的context属性设为never属于错误用法,never类型表示不存在的值的类型,无法参与正常的条件判断,TS不会将其作为合法的判别分支。
  2. 条件判断逻辑不符合类型收窄规则:使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 15:06:03