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

TypeScript泛型中判别式属性类型不生效问题求助

TypeScript类型收窄问题:条件判断中data类型未正确推断

我尝试基于Schema创建并推断类型,但在if判断代码块中,data的类型不符合预期——它应该是{ love: string },而非{ love: string } | { eat: string }。

问题代码示例

const users = {
    //...
}

// 类似zod的'z.infer',从users schema生成的示例类型
type Users = {
    henry: {
        data: {
            love: string;
        };
    };
    kyle: {
        data: {
            eat: string;
        };
    };
};

type UserMessage<U extends keyof Users = keyof Users> = {
    user: U
    data: Users[U]['data']
}

// 未知类型的示例输入
const test: unknown = { user: 'henry', data: { love: 'kyle'}}
const typed = test as UserMessage

if (typed.user === 'henry') {
    typed.data // 类型:{ love: string } | { eat: string } —— 不符合预期
}

解决方法

1. 将UserMessage改为可区分联合类型

原来的UserMessage是带默认泛型的泛型类型,生成的是单个对象类型而非联合类型,TypeScript无法通过user字段收窄data的类型。我们可以调整类型定义,让它直接生成可区分联合类型:

type Users = {
    henry: {
        data: {
            love: string;
        };
    };
    kyle: {
        data: {
            eat: string;
        };
    };
};

// 生成联合类型:{ user: 'henry', data: { love: string } } | { user: 'kyle', data: { eat: string } }
type UserMessage = {
    [U in keyof Users]: {
        user: U;
        data: Users[U]['data'];
    };
}[keyof Users];

const test: unknown = { user: 'henry', data: { love: 'kyle'}}
const typed = test as UserMessage

if (typed.user === 'henry') {
    typed.data // 类型:{ love: string } —— 符合预期
}

这种方法下,UserMessage是两个具体对象类型的联合,TypeScript能识别user是联合类型的区分字段,当判断typed.user === 'henry'时,自动将typed收窄为对应的子类型,data的类型也就正确了。

2. 使用自定义类型守卫函数

如果不想修改UserMessage的定义,可以通过自定义类型守卫来明确类型收窄规则:

type Users = {
    henry: {
        data: {
            love: string;
        };
    };
    kyle: {
        data: {
            eat: string;
        };
    };
};

type UserMessage<U extends keyof Users = keyof Users> = {
    user: U
    data: Users[U]['data']
}

// 自定义类型守卫,判断是否为henry的消息
function isHenryMessage(msg: UserMessage): msg is UserMessage<'henry'> {
    return msg.user === 'henry';
}

const test: unknown = { user: 'henry', data: { love: 'kyle'}}
const typed = test as UserMessage

if (isHenryMessage(typed)) {
    typed.data // 类型:{ love: string } —— 符合预期
}

类型守卫函数通过msg is UserMessage<'henry'>告诉TypeScript:当函数返回true时,msg的类型就是UserMessage<'henry'>,从而实现精确的类型收窄。


内容的提问来源于stack exchange,提问作者SonMooSans

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 09:41:12