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

如何实现支持泛型函数的TypeScript柯里化工具函数?

支持泛型函数的TypeScript柯里化工具实现

问题背景

现有一款柯里化工具函数无法处理泛型函数的柯里化需求,期望实现如下效果:

const example_curry = curry(<T>(name: string, int: number): Promise<T> => {
  return Promise.resolve(int as unknown as T);
});
const named_curry = example_curry('name');
const curry_result = named_curry<string>(5); // 可在柯里化后的函数中指定泛型类型

原工具代码因未考虑泛型参数传递逻辑,无法支持上述用法。

解决方案

核心思路是让柯里化后的函数能够接收并传递原函数的泛型参数,以下是修改后的完整实现:

类型定义调整

/* eslint-disable @typescript-eslint/no-explicit-any */

// 生成可选参数元组,支持部分传参场景
type PartialTuple<TUPLE extends any[], EXTRACTED extends any[] = []> = 
  TUPLE extends [infer NEXT_PARAM, ...infer REMAINING]
    ? PartialTuple<REMAINING, [...EXTRACTED, NEXT_PARAM?]>
    : [...EXTRACTED, ...TUPLE];

// 获取函数的可选参数元组类型
type PartialParameters<FN extends (...args: any[]) => any> = PartialTuple<Parameters<FN>>;

// 计算剩余需要传入的参数类型
type RemainingParameters<PROVIDED extends any[], EXPECTED extends any[]> = 
  EXPECTED extends [infer E1, ...infer EX]
    ? PROVIDED extends [infer P1, ...infer PX]
      ? P1 extends E1
        ? RemainingParameters<PX, EX>
        : never
      : EXPECTED
    : [];

// 柯里化函数类型:支持原函数的泛型参数传递
type CurriedFunction<PROVIDED extends any[], FN extends <T extends any[]>(...args: any[]) => any> = 
  <T extends any[], NEW_ARGS extends PartialTuple<RemainingParameters<PROVIDED, Parameters<FN<T>>>>>(
    ...args: NEW_ARGS
  ) => CurriedFunctionOrReturnValue<PROVIDED, FN, T, NEW_ARGS>;

// 判断返回值是柯里化函数还是原函数的返回值
type CurriedFunctionOrReturnValue<
  PROVIDED extends any[],
  FN extends <T extends any[]>(...args: any[]) => any,
  T extends any[],
  NEW_ARGS extends any[]
> = 
  RemainingParameters<[...PROVIDED, ...NEW_ARGS], Parameters<FN<T>>> extends [any, ...any[]]
    ? CurriedFunction<[...PROVIDED, ...NEW_ARGS], FN>
    : ReturnType<FN<T>>;

// 兼容泛型与非泛型函数的统一类型
type CurryableFunction = 
  | (<T extends any[]>(...args: any[]) => any)
  | ((...args: any[]) => any);

柯里化函数实现

export default function curry<FN extends CurryableFunction, STARTING_ARGS extends PartialParameters<FN>>(
  targetFn: FN,
  ...existingArgs: STARTING_ARGS
): 
  FN extends <T extends any[]>(...args: any[]) => any
    ? CurriedFunction<STARTING_ARGS, FN>
    : CurriedFunction<STARTING_ARGS, FN> {
  return function(...args) {
    const totalArgs = [...existingArgs, ...args];
    if (totalArgs.length >= targetFn.length) {
      return targetFn(...totalArgs);
    }
    return curry(targetFn, ...(totalArgs as PartialParameters<FN>));
  } as any;
}

验证示例

使用修改后的工具,可实现期望的泛型柯里化效果:

const example_curry = curry(<T>(name: string, int: number): Promise<T> => {
  return Promise.resolve(int as unknown as T);
});

const named_curry = example_curry('Alice');
const curry_result = named_curry<string>(123); // 类型为Promise<string>
const curry_result_num = named_curry<number>(456); // 类型为Promise<number>

关键改动说明

  • 重构CurriedFunction类型,使其支持接收原函数的泛型参数并传递到参数、返回值类型计算中
  • 新增CurryableFunction类型,同时兼容泛型与非泛型函数的柯里化需求
  • 调整返回值类型判断逻辑,确保泛型参数能正确传递到原函数的返回值

内容的提问来源于stack exchange,提问作者Jonathan Woolf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 20:05:00