// 函数范型,部分开始参数
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>));
};
}
// 柯里化后的返回值,参数(NEW_ARGS)是剩余参数的一部分,如果参数不够则需要迭代
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
any> = RemainingParameters<
PROVIDED,
Parameters
> extends [any, ...any[]]
: ReturnType;
type PartialTuple =
// If the tuple provided has at least one required value
TUPLE extends [infer NEXT_PARAM, ...infer REMAINING]
? // recurse back in to this type with one less item
// in the original tuple, and the latest extracted value
// added to the extracted list as optional
PartialTuple
: // else if there are no more values,
// return an empty tuple so that too is a valid option
[...EXTRACTED, ...TUPLE];
type PartialParameters
any> = PartialTuple>;
// 获取剩余参数,提供的参数类型必须符合期望参数类型
type RemainingParameters
=
// if the expected array has any required items…
EXPECTED extends [infer E1, ...infer EX]
? // if the provided array has at least one required item
PROVIDED extends [infer P1, ...infer PX]
? // if the type is correct, recurse with one item less
//in each array type
P1 extends E1
: // else return this as invalid
never
: // else the remaining args is unchanged
EXPECTED
: // else there are no more arguments
[];