泛型函数中联合类型的keyof安全类型标注问题
问题解析:为什么
keyof T没解析成'name' | 'fleas'? 先看你的代码:
type MyAnimals = { name: "dog", fleas: 2 } | { name: "cat" } function GetKeys<T extends MyAnimals>(animal: T) { for (let k in animal) { const keyAsKeyOf = k as keyof T; // ^? const keyAsKey: keyof T // 为什么不是`name`? } }
核心原因:TypeScript中keyof对联合类型的处理逻辑
当keyof作用于联合类型时,它不会取所有成员键的并集,而是取所有成员的共有键的交集。
你的T是MyAnimals的子类型,而MyAnimals是两个对象类型的联合:
- 第一个成员的键是
'name' | 'fleas' - 第二个成员的键是
'name'
两者的共有键只有'name',所以TypeScript在泛型函数的上下文里,会把keyof T推断为这个共有键'name'——因为泛型T可以是联合类型中的任意一个成员,TypeScript必须保证类型安全,只能取所有可能情况都存在的键。
如果想提取联合类型所有成员的键的并集,可以用分布式条件类型实现:
type AllKeys<T> = T extends unknown ? keyof T : never; type AnimalKeys = AllKeys<MyAnimals>; // 得到 'name' | 'fleas'
但回到你的循环场景:for...in遍历的是当前传入对象的实际键,但因为T是泛型,TypeScript编译期无法确定它具体指向联合中的哪一个成员,所以只能用共有键做类型推断。
内容的提问来源于stack exchange,提问作者Slava Knyazev
相关产品推荐
相关产品推荐

