下面是来自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 机制还不够了解更明智地解决这个问题。感谢您的宝贵时间!
说实话,我没有完全阅读这个问题,但我猜你想柯里化一个函数并保留它的泛型。
您可以执行以下操作:
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
如果您想要自定义返回类型,那么您可以为重载引入泛型。