如何使用infer推断泛型函数?重载函数泛型推断失效怎么解决?
TypeScript泛型函数类型处理的两个问题及解决方案
一、infer提取泛型函数类型时丢失泛型的原因及解决
问题根源
TypeScript中,当泛型函数类型被作为类型参数传入时,会被自动实例化为具体类型,而非保留泛型的模板结构。
你传入Fn<T>的<V>(v: V) => V,会被TypeScript视为一个能接受任意类型参数、返回对应类型的函数,最终退化成(param: unknown) => unknown。infer只能从具体的函数类型中提取参数和返回值,无法识别并保留原函数的泛型声明。
解决方案:用泛型高阶类型保留结构
要保留泛型函数的泛型特性,需要直接在类型定义中传递泛型参数,而非通过infer提取:
// 定义支持泛型传递的高阶类型 export type GenericFnWrapper = <V>(param: V) => V; // 直接使用即可保留泛型结构:type F = <V>(param: V) => V type F = GenericFnWrapper;
如果需要基于原泛型函数做类型转换,可以定义带泛型参数的高阶类型:
export type Fn<T> = <V extends T>(param: V) => V; // F的类型为 <V extends unknown>(param: V) => V,即等价于<V>(param: V) => V type F = Fn<unknown>;
二、重载函数传入后泛型推断失效的解决方法
问题根源
重载函数作为参数传递时,TypeScript只会使用最后一个重载(实现签名)进行类型推断,且外层函数fn的泛型参数P、R无法自动关联重载内部的<S>泛型,导致返回函数丢失泛型特性。
解决方案:让外层泛型与重载泛型绑定
调整fn的定义,使其泛型参数直接关联重载函数内部的泛型:
方法1:显式定义重载函数的泛型类型
// 定义带泛型的重载函数类型 type OverloadedGenericFn<S> = { (): ""; (param: S): S; }; // 让fn的泛型S与重载函数的泛型绑定 export function fn<S>(cb: OverloadedGenericFn<S>) { return (param: S, extra?: unknown) => { console.log(extra); return cb(param); }; } // 现在f被推断为泛型函数:const f: <S>(param: S, extra?: unknown) => S const f = fn({} as unknown as OverloadedGenericFn<any>); const returned = f({ value: "value" as const }); // typeof returned 为 { value: "value" }
方法2:让fn直接接受泛型重载函数
export function fn<T>(cb: { (): ""; <U>(param: U): U }) { return <U>(param: U, extra?: unknown) => { console.log(extra); return cb(param); }; } // f的类型为:const f: <U>(param: U, extra?: unknown) => U const f = fn({} as unknown as { (): ""; <U>(param: U): U }); const returned = f({ value: "value" as const }); // typeof returned 为 { value: "value" }
核心是让外层函数的泛型参数与重载内部的泛型参数建立关联,确保TypeScript能正确推断返回函数的泛型结构。
内容的提问来源于stack exchange,提问作者Abdulramon jemil
相关产品推荐
相关产品推荐

