TypeScript泛型推断映射类型使用extends的校验异常问题
TypeScript 嵌套泛型类型推导失效问题
问题复现
以下是问题代码及相关Playground链接:
type SomeType<T> = { [K in keyof T]?: K extends 'u' ? string : T[K] extends object ? SomeType<T[K]> : object } function someType<T>(t: SomeType<T>) { return t; } type BLA = SomeType<{ u: 1, b: { u: 1, }, }>; const blaBLA: BLA = { u: 1, // <-- 正确报错:Type 'number' is not assignable to type 'string'. b: { u: 1, // <-- 正确报错:Type 'number' is not assignable to type 'string'. }, }; const bla = someType({ u: 1, // <-- 正确报错:Type 'number' is not assignable to type 'string'. b: { u: 1, // <-- 预期出现上述相同报错 // 实际b属性的值被解析为'object'类型,而非'SomeType<T[K]>' }, });
异常表现:
- 显式标注
BLA类型的变量blaBLA,两层u字段赋值数字1都能正确触发类型报错 - 直接调用
someType传入对象字面量时,仅顶层u字段会报错,嵌套在b属性下的u字段没有触发类型校验
原理说明
该现象是TypeScript泛型反向推导的性能优化截断机制导致的:
- 显式标注类型时,TS会完整展开目标类型,递归校验所有嵌套字段的约束,因此不会出现校验遗漏。
- 通过
someType<T>(t: SomeType<T>)这种写法调用函数时,TS需要从传入的参数t反向推导泛型参数T。为了控制编译时长,TS在推导嵌套层级的条件类型时,遇到宽泛的object类型匹配会直接命中分支,停止向内层递归展开映射类型。 - 由于
{u:1}本身是合法的object类型值,命中分支后TS不会再校验对象内部的字段规则,最终导致嵌套层的u字段没有触发类型检查。
修复方案
调整函数的泛型约束逻辑,避免反向推导时的递归截断:
type SomeType<T> = { [K in keyof T]?: K extends 'u' ? string : T[K] extends object ? SomeType<T[K]> : object } // 修改泛型约束:直接推导参数类型为T,再校验T满足SomeType<T>的递归规则 function someType<T extends SomeType<T>>(t: T) { return t; }
修复后逻辑:
- TS会直接将传入的对象字面量类型推导为泛型
T,不需要从SomeType<T>反向推导T - 推导完成后TS会递归校验
T是否满足SomeType<T>的所有层级约束,嵌套层的b.u字段就会正确抛出类型错误,和显式标注类型的表现完全一致。
内容的提问来源于stack exchange,提问作者Page not found
相关产品推荐
相关产品推荐

