You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:45:47