TypeScript对象字面量联合类型计算属性赋值异常问题
TypeScript函数内外类型检查差异问题解析
先看核心代码:
declare const GenderChoices: { readonly Male: "Male"; readonly Female: "Female"; }; type GenderChoice = (typeof GenderChoices)[keyof typeof GenderChoices]; type Person = { id: number; name: string; }; type PersonById = Record<number, Person>; type PersonByGender = Partial<Record<GenderChoice, PersonById>>; // 函数外部:报错 const gender: GenderChoice = "Male"; const obj = { [gender]: false }; const personByGender: PersonByGender = obj; // 类型不匹配报错 // 函数内部:正常通过 function testFunction(gender: GenderChoice) { const obj = { [gender]: false }; const personByGender: PersonByGender = obj; // 无错误 }
原因拆解
1. 函数外部的类型推断逻辑
外部的gender是直接赋值"Male"的常量,TypeScript会自动类型收窄——把它的类型从GenderChoice联合类型缩小为具体的字面量类型"Male"。
因此,obj的类型会被精准推断为:
{ Male: boolean; }
而PersonByGender要求Male/Female属性的值必须是PersonById类型(或不存在),boolean类型和PersonById完全不兼容,所以触发类型报错。
2. 函数内部的类型推断逻辑
函数参数gender的类型是完整的GenderChoice联合类型(未被收窄),当用联合类型作为计算属性名时,TypeScript会把obj推断为具有联合类型所有键的可选索引签名:
{ [x in GenderChoice]?: boolean; }
此时TypeScript会采用宽松的兼容性规则:只要两个类型的索引签名结构一致(键的范围相同、都是可选),就允许赋值——哪怕值类型看起来不匹配。这是因为函数参数的联合类型是“通用”的,TypeScript无法确定具体会使用哪个键,因此放宽了检查标准。
解决方案
如果想让外部代码也通过类型检查,可以用两种方式调整:
方式1:手动指定
obj的类型const obj: PersonByGender = { [gender]: false };方式2:阻止
gender的类型收窄const gender: GenderChoice = "Male" as GenderChoice; const obj = { [gender]: false }; const personByGender: PersonByGender = obj;
内容的提问来源于stack exchange,提问作者Kunal Kumar
相关产品推荐
相关产品推荐

