TypeScript多泛型自动推断:两种写法为何表现不同?
TypeScript泛型推断差异的原因解析
问题场景
你尝试通过extends关键字让TypeScript自动推断第二个泛型类型,第一种写法报错要求指定第二个泛型,而柯里化后的写法却能自动推断:
第一种写法(报错)
function b<T, U extends Partial<T>>(u: U) { return u } b<User>({name: 'string'}) // 提示:expected 2 type arguments, but got 1
第二种写法(正常推断)
function b<T>() { return function<P extends Partial<T>>(p: P) { return p } } b<User>()({name: 'string'}) // 自动推断P的类型
核心原因
1. 同一层级泛型的限制
第一种写法中,T和U是同一层级的泛型参数。TypeScript的规则是:当你手动指定部分泛型参数时,必须显式指定所有泛型参数——哪怕其中一个的约束依赖于另一个。
虽然U的约束U extends Partial<T>依赖于T,但编译器不会在你只传T的情况下,自动根据函数参数去推断U。它不支持“混合指定+推断”的模式(TypeScript 4.7+支持用_占位符实现部分推断,比如b<User, _>({name: 'string'}),但这是语法糖,并非默认行为)。
2. 柯里化拆分泛型阶段
第二种写法通过柯里化把函数拆成两层,将泛型参数的处理分成了两个独立阶段:
- 第一阶段调用
b<User>()时,你显式固定了T的类型,此时内层函数的约束P extends Partial<T>已经有了明确的依赖基准。 - 第二阶段调用内层函数时,编译器可以单独根据传入的参数
{name: 'string'},反向推断出符合Partial<User>约束的P类型——因为此时T已经确定,P的推断不再依赖未指定的泛型,完全可以自动完成。
简单来说,柯里化把相互依赖的泛型参数拆到不同层级,让编译器可以分阶段处理:先固定上层泛型,再自动推断下层泛型,完美避开了同一层级泛型的“全指定或全推断”限制。
内容的提问来源于stack exchange,提问作者ColdDarkness
相关产品推荐
相关产品推荐

