TypeScript中函数经类包装后泛型类型推断失效问题
类型推断失效原因
核心差异来自TypeScript对高阶泛型函数(即自身带泛型参数的函数,比如示例中的identity函数<T>(t:T)=>T)的推断规则边界:
- 原始
compose函数的返回类型是直接的函数类型(a:A)=>C,处于TS支持的高阶类型推断场景:TS会延迟对传入泛型函数的类型实例化,保留函数自身的泛型签名,最终能正确推导出多态返回类型。 wrapCompose的写法把组合后的函数类型作为泛型参数传入Wrapper<T>,同时顶层泛型参数A/B/C对应的参数位置是单态函数签名(a:A)=>B、(b:B)=>C:TS在推断A/B/C时,会先尝试将传入的多态函数实例化为匹配单态签名的具体类型,由于没有额外上下文约束,泛型参数会被默认填充为unknown,最终得到Wrapper<(a:unknown)=>unknown>的错误结果,丢失了原函数的泛型信息。
这个推断过程发生在函数类型检查的最早期,不会被函数内部实现的返回值影响,所以哪怕内部调用的compose本身类型正确,也无法修正已经被错误推断的A/B/C类型。简单说就是:TS不会在泛型类型参数的嵌套位置保留多态函数的泛型签名,会提前将其拍平为非泛型的具体类型,无上下文时就回退到unknown。
可行修复方案
核心思路是不要提前将传入函数拆分为单态的输入/输出泛型参数,而是先通过泛型约束捕获传入函数的完整类型(包括自身的泛型签名),再通过类型工具推导组合后的函数类型。
具体实现代码如下:
class Wrapper<T> { constructor(public readonly value: T) { } } function wrapCompose< F extends (arg: any) => any, G extends (arg: ReturnType<F>) => any >(f: F, g: G): Wrapper<(arg: Parameters<F>[0]) => ReturnType<G>> { return new Wrapper(a => g(f(a))); }
验证推断结果:
const correct = wrapCompose(<T>(t: T) => t, <T>(t: T) => t); // 推断结果为 Wrapper<<T>(arg: T) => T>,完全符合预期
这种写法生效的原因是:F和G是直接的类型参数,TS在匹配extends约束时,会完整捕获传入函数的所有类型信息(包括多态泛型签名),不会提前做单态实例化;后续通过Parameters、ReturnType工具类型推导组合函数类型时,就能完整保留原函数的泛型特性。
如果需要支持更多函数的组合(比如3个及以上函数compose),只需要按同样的逻辑新增对应的泛型参数捕获,或者写递归的泛型类型处理变长函数参数即可。
内容的提问来源于stack exchange,提问作者Juan
相关产品推荐
相关产品推荐

