为何TypeScript中泛型函数内的索引类型被推断为never?
问题分析
先看你给出的代码:
type X = { aa: number; bb: string }; const get = <Key extends keyof X>(key: Key) => { type T<Value extends X[Key]> = Value; const a: T<any>; /** * 类型“string”不满足约束“X[Key]”。 类型“string”不能赋值给类型“never”。 */ const b: T<string>; };
核心原因:泛型参数的作用域与类型收缩
- 外层泛型Key的特性:
get函数的泛型Key是调用时确定的单一类型,它要么是"aa"要么是"bb",而非同时包含两者的联合类型。在函数内部编写代码时,TypeScript并不知道Key最终会是哪一个具体值,只会把它当成一个「未知的特定键」。 - X[Key]的类型推导:因为
Key是未知的特定键,X[Key]对应的是单一类型(要么number要么string),而不是number | string。当你尝试给内部泛型T传入string时,TypeScript需要验证string是否能满足X[Key]的约束——但由于Key可能是"aa"(此时X[Key]是number),string无法同时适配number和string两种可能的约束,所以TypeScript会取两种约束的交集:number & string,而这个交集的结果就是never。 - 你误解的点:你以为
X[Key]是number | string,但实际上在泛型函数内部,Key是「单一值的占位符」,不是联合类型,所以X[Key]也不会是联合类型。只有当直接把Key写成keyof X时,X[keyof X]才会是number | string。
验证示例
把get函数的调用场景具体化,就能看清楚逻辑:
- 当调用
get("aa")时,Key是"aa",X[Key]是number,此时T的约束就是number,传入string自然会报错; - 当调用
get("bb")时,Key是"bb",X[Key]是string,此时T<string>是完全合法的。
但在函数内部编写代码时,TypeScript必须保证代码能适配所有可能的Key值,所以它不会假设Key是某一个特定值,而是取所有可能情况的交集,最终得到never。
内容的提问来源于stack exchange,提问作者Guichi
相关产品推荐
相关产品推荐

