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
相关产品推荐
相关产品推荐

