如何在TypeScript中手动柯里化重载函数?类型问题求解
解决TypeScript重载函数的柯里化类型问题
这个问题我之前也碰到过——TypeScript对重载函数的泛型推导确实有点“轴”,默认只会抓取最后一个重载签名,导致你的curriedFn只能匹配(b: boolean, p: any): number这一项。不过有两种靠谱的解决方案,咱们一步步来聊:
方案一:手动定义柯里化函数的重载
如果原函数的重载数量不多,最直接的方式就是给柯里化后的函数手动对应每个重载:
interface ComplicatedFunction { (n: number, p: any): string; (s: string, p: any): number; (b: boolean, p: any): number; } declare const fn: ComplicatedFunction; // 给curriedFn定义与原函数对应的重载 const curriedFn: { (n: number): (p: any) => string; (s: string): (p: any) => number; (b: boolean): (p: any) => number; } = (p1: number | string | boolean) => (p2: any) => fn(p1 as any, p2);
优点&缺点
- ✅ 类型检查完全精准,调用时会根据传入的
p1类型自动提示返回值类型 - ❌ 如果原函数有大量重载,手动写会很繁琐
方案二:用条件类型自动生成柯里化重载
如果想更通用一点,可以利用TypeScript的条件类型,自动把原函数的重载转换成柯里化版本:
首先定义一个工具类型,专门处理二元重载函数的柯里化转换:
// 提取三元重载函数的柯里化类型(对应你的场景) type CurryBinaryOverloads<T> = T extends { (...args: [infer P1a, infer P2a]): infer Ra; (...args: [infer P1b, infer P2b]): infer Rb; (...args: [infer P1c, infer P2c]): infer Rc; } ? ((p1: P1a) => (p2: P2a) => Ra) & ((p1: P1b) => (p2: P2b) => Rb) & ((p1: P1c) => (p2: P2c) => Rc) : never; // 通用柯里化函数,指定返回类型为转换后的重载集合 const curry2 = <T extends (...args: any[]) => any>(fn: T): CurryBinaryOverloads<T> => { return (p1: any) => (p2: any) => fn(p1, p2); }; // 现在curriedFn会匹配所有原函数的重载 const curriedFn = curry2(fn); // 测试:类型推断完全正确 const strResult = curriedFn(123)('param'); // strResult类型为string const numResult1 = curriedFn('hello')('param'); // numResult1类型为number const numResult2 = curriedFn(true)('param'); // numResult2类型为number
扩展说明
如果你的函数有更多重载,只需要在CurryBinaryOverloads的条件类型里继续添加分支即可。这种方式的核心是利用交叉类型把多个柯里化函数类型合并,让TypeScript能识别所有重载。
为什么你原来的泛型方案不行?
当你把重载函数传入普通泛型函数时,TypeScript会将其解析为函数的实现签名(也就是最后一个重载),所以P1被推断为boolean,R为number,自然就丢失了前面的两个重载。只有显式处理重载类型,才能保留所有签名信息。
内容的提问来源于stack exchange,提问作者Zheeeng
相关产品推荐
相关产品推荐

