TypeScript中如何用具体类型包装泛型函数的回调并实现正确类型推导
TypeScript中如何用具体类型包装泛型函数的回调并实现正确类型推导
看起来你想要实现一个包装函数,它能接收任意单参数泛型函数,调用时传入string类型的参数,并且正确推导该泛型函数在类型参数为string时的返回类型。我来帮你解决这个问题,先看最终的可行方案:
declare function generic1<T>(t: T): T; declare function generic2<T>(t: T): { a: T }; declare function generic3<T>(t: T): { b: T[] }; // 正确的类型定义 function string_wrapper<F extends <T>(t: T) => any>(f: F): F extends <T>(t: T) => infer R ? R extends unknown ? R : never : never { return f('hi') as any; } const r1 = string_wrapper(generic1); // 类型:string ✅ const r2 = string_wrapper(generic2); // 类型:{ a: string } ✅ const r3 = string_wrapper(generic3); // 类型:{ b: string[] } ✅
方案细节解释
泛型约束
F extends <T>(t: T) => any
这里我们把F约束为泛型函数类型,确保传入的f是一个接受单个泛型参数T的函数,而不是已经被实例化为具体类型的函数。这一步是保留原函数泛型信息的关键。返回类型的推断逻辑
F extends <T>(t: T) => infer R ? R extends unknown ? R : never : never
我们使用TypeScript的条件类型和infer关键字来提取:当泛型函数F的类型参数T被指定为string时,它的返回类型是什么。infer R会自动推断出F在T=string时的返回类型R,最终返回这个R。类型断言
as any
由于TypeScript编译器暂时无法自动识别f('hi')的类型完全匹配我们推断出的R,所以需要一个类型断言来让编译器通过类型检查。这个断言是安全的,因为我们已经通过条件类型确保了f('hi')的类型就是我们需要的R。
更简洁的等价写法
我们也可以结合TypeScript内置的ReturnType工具类型来简化返回类型的定义,效果完全一致:
function string_wrapper<F extends <T>(t: T) => any>(f: F): ReturnType<(F extends { (t: string): infer R } ? F : never)> { return f('hi') as ReturnType<(F extends { (t: string): infer R } ? F : never)>; }
为什么你之前的尝试不生效
- 第一个尝试的泛型约束
F extends <T>(t: T) => any方向是对的,但缺少基于infer的类型提取逻辑,无法正确推断T=string时的返回结果。 - 后面将
F约束为(t: string) => any的写法,会让TypeScript自动将传入的泛型函数实例化为具体的函数类型(比如generic1会被推断为(t: string) => string),虽然能得到正确的返回类型,但丢失了原函数的泛型信息,不符合你想要保留F作为泛型函数类型的核心需求。
备注:内容来源于stack exchange,提问作者Miguel Leon
相关产品推荐
相关产品推荐

