具有泛型函数的 Typescript Curry 函数

问题描述 投票:0回答:1

下面是来自medium.com 文章的打字稿咖喱函数定义,非常简洁。我想知道是否有可能创建一个像这样的打字稿咖喱函数,它允许具有泛型的函数。或者至少是一种创建柯里函数的方法,您可以或多或少地指定自定义返回类型。

例如

const example_curry = curry(<T>(name: string, int: number): Promise<T> => {...});
const named_curry = example_curry('name');
const curry_result = named_curry<string>(5);
/* eslint-disable @typescript-eslint/no-explicit-any */
// curry utilty type from https://medium.com/codex/currying-in-typescript-ca5226c85b85

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 (...args: any[]) => any
> = <
  NEW_ARGS extends PartialTuple<RemainingParameters<PROVIDED, Parameters<FN>>>
>(
  ...args: NEW_ARGS
) => CurriedFunctionOrReturnValue<[...PROVIDED, ...NEW_ARGS], FN>;

type CurriedFunctionOrReturnValue<
  PROVIDED extends any[],
  FN extends (...args: any[]) => any
> = RemainingParameters<PROVIDED, Parameters<FN>> extends [any, ...any[]]
  ? CurriedFunction<PROVIDED, FN>
  : ReturnType<FN>;

export default function curry<
  FN extends (...args: any[]) => any,
  STARTING_ARGS extends PartialParameters<FN>
>(
  targetFn: FN,
  ...existingArgs: STARTING_ARGS
): 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>));
  };
}

我尝试过用返回的通用值重写定义,或者让 curry 返回类似

function<T>
之类的东西,但最后我只是猜测和检查,因为我对底层 TS 机制还不够了解更明智地解决这个问题。感谢您的宝贵时间!

typescript generics currying curry
1个回答
0
投票

说实话,我没有完全阅读这个问题,但我猜你想柯里化一个函数并保留它的泛型。

您可以执行以下操作:

type CurryOverload = {
  <A, R>(cb: (p1: A) => R): (p1: A) => R;
  <A, B, R>(cb: (p1: A, p2: B) => R): (p1: A) => (p2: B) => R;
  <A, B, C, R>(cb: (p1: A, p2: B, p3: C) => R): (p1: A) => (p2: B) => (p3: C) => R;
  // todo: add more later
};

const curry: CurryOverload = (() => {}) as any;

const result = curry(<N>(name: N, age: number) => name); // => const result: <N>(p1: N) => (p2: number) => N

如果您想要自定义返回类型,那么您可以为重载引入泛型。

© www.soinside.com 2019 - 2024. All rights reserved.