无法在联合复合类型中使用never的TypeScript问题求助
问题:联合类型构造函数赋值报错
我尝试用对象作为构造函数输入初始化类,该对象仅能填充两个字段中的一个,但在构造函数内解析时触发了错误。期望以下简化代码可以正常运行:
type Props = { name: string; age: never } | { name: never; age: number }; class Person { data: Props; constructor(data: Props) { if (data.name !== undefined) { this.data = data; } else { this.data = { // 此行触发错误 ...data, age: data.age * 1.5, // 即使直接写"data.age"仍会触发错误 }; } } }
遇到的错误:
Type '{ age: number; name: string; }' is not assignable to type '{ name: never; age: number; }'.
Types of property 'name' are incompatible.
Type 'string' is not assignable to type 'never'.
问题原因
TypeScript 对联合类型的收窄在这里没有正确生效:当判断 data.name !== undefined 进入 else 分支后,理论上应该推断出 data 是 { name: never; age: number } 类型,但展开 ...data 时,never 类型的 name 字段被错误保留,导致新对象的类型被推断为包含 name: string(来自联合类型的另一分支),从而与 Props 类型冲突。
解决方法
方法1:调整 Props 类型定义(推荐)
将 never 替换为可选的 never(即字段不存在),让 TypeScript 能更准确地进行类型收窄:
// 修改后的 Props 类型 type Props = { name: string; age?: never } | { name?: never; age: number }; class Person { data: Props; constructor(data: Props) { if (data.name !== undefined) { this.data = data; } else { // 此时 TypeScript 明确知道 data 只有 age 字段,无需处理 name this.data = { age: data.age * 1.5 }; } } }
方法2:使用类型断言明确类型
在 else 分支中手动断言 data 的类型,避免类型推断错误:
type Props = { name: string; age: never } | { name: never; age: number }; class Person { data: Props; constructor(data: Props) { if (data.name !== undefined) { this.data = data; } else { // 断言为仅含 age 的分支类型 const ageData = data as { name: never; age: number }; this.data = { age: ageData.age * 1.5 } as { name: never; age: number }; } } }
方法3:自定义类型守卫函数
通过类型守卫函数让 TypeScript 更清晰地识别联合类型分支:
type Props = { name: string; age: never } | { name: never; age: number }; // 自定义类型守卫,判断是否为含 age 的分支 function isAgeProps(data: Props): data is { name: never; age: number } { return typeof (data as { name: never; age: number }).age === 'number'; } class Person { data: Props; constructor(data: Props) { if (data.name !== undefined) { this.data = data; } else if (isAgeProps(data)) { this.data = { age: data.age * 1.5 }; } else { throw new Error('无效的 Props 参数'); } } }
内容的提问来源于stack exchange,提问作者GalAbra
相关产品推荐
相关产品推荐

