TypeScript 杂记六 《柯里化》
Posted 左手121
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript 杂记六 《柯里化》相关的知识,希望对你有一定的参考价值。
TypeScript 杂记六 《柯里化》
说明
简单通过一个示例说明柯里化的结果
const add = (a: number, b: number, c: number) => a + b + c;
add(1, 1, 1);
// 柯里化之后的效果
const curriedAdd = DynamicParamsCurrying(add);
curriedAdd(1, 2, 3);
curriedAdd(1, 2)(4);
curriedAdd(2)(3)(4);
思路
- 简单定义一个主函数
declare function DynamicParamsCurrying<T extends unknown[], R>(
func: (...args: T) => R
): CurriedFunction<T, R>;
-
具体的 CurriedFunction 实现
- 先假设固定 3 个参数则定义如下,如下示例:
interface Func1<T1, R> (): Func1<T1, R>; (t1: T1): R; interface Func2<T1, T2, R> (): Func2<T1, T2, R>; (t1: T1): Func1<T2, R>; (t1: T1, t2: T2): R; interface Func3<T1, T2, T3, R> (): Func3<T1, T2, T3, R>; (t1: T1): Func2<T2, T3, R>; (t1: T1, t2: T2): Func1<T3, R>; (t1: T1, t2: T2, t3: T3): R; interface Curry <T1, T2, T3, R>(func: (t1: T1, t2: T2, t3: T3) => R): Func3<T1, T2, T3, R>;
-
根据上述我们思考一下如何动态生成
- 如果参数传完了则返回对应的结果
- 如果不传参数,则重新来一次
type CurriedFunction<T extends unknown[], R> = T extends [] ? R : (): CurriedFunction<T, R> & CurriedDynamicFunction<T, R>;
- 动态生成每一次递归的所有的函数,每次可以传递 1 - N 个参数
type CurriedDynamicFunction< T extends unknown[], R, H extends unknown[] = [] > = T extends [infer L, ...infer N] ? // 第一次传入第一个参数 (...args: [...H, L]): CurriedFunction<N, R>; & (N extends [] ? // 如果没有更多的参数则停止 : // 剔出第一个参数,传入下一次 // 并将这个值存到 H 中,这样第二次上边传入的参数就是 2个 // 依次类推 CurriedDynamicFunction<N, R, [...H, L]>) : R;
-
考虑如果没有入参的情况下,改动一下主函数
declare function DynamicParamsCurrying<T extends unknown[], R>(
func: (...args: T) => R
): T extends [] ? (): R : CurriedFunction<T, R>;
最终结果
type CurriedDynamicFunction<
T extends unknown[],
R,
H extends unknown[] = []
> = T extends [infer L, ...infer N]
?
(...args: [...H, L]): CurriedFunction<N, R>;
& (N extends [] ? : CurriedDynamicFunction<N, R, [...H, L]>)
: R;
type CurriedFunction<T extends unknown[], R> = T extends []
? R
: (): CurriedFunction<T, R> & CurriedDynamicFunction<T, R>;
declare function DynamicParamsCurrying<T extends unknown[], R>(
func: (...args: T) => R
): T extends [] ? (): R : CurriedFunction<T, R>;
测试
- 为了方便测试结果我们先去掉不传入参数的情况,改动一下 CurriedDynamicFunction 和 DynamicParamsCurrying
type CurriedDynamicFunction<
T extends unknown[],
R,
H extends unknown[] = []
> = T extends [infer L, ...infer N]
?
(...args: [...H, L]): CurriedDynamicFunction<N, R>; // 这里变一下
& (N extends [] ? : CurriedDynamicFunction<N, R, [...H, L]>)
: R;
declare function DynamicParamsCurrying<T extends unknown[], R>(
func: (...args: T) => R
): T extends [] ? (): R : CurriedDynamicFunction<T, R>; // 这里变一下
const test1 = DynamicParamsCurrying(() => 0);
// 返回的类型: () => number;
const test2 = DynamicParamsCurrying((a: number) => a);
// 返回的类型: (args_0: number) => number;
const test3 = DynamicParamsCurrying((a: number, b: number) => a + b);
/*
返回的类型:
((args_0: number) => (args_0: number) => number) &
((args_0: number, args_1: number) => number);
*/
- 不改动的效果
const test3 = DynamicParamsCurrying((a: number, b: number) => a + b);
const a = test3(1, 2);
const b = test3(1)(2);
const c = test3()()()(1)()()()(2);
以上是关于TypeScript 杂记六 《柯里化》的主要内容,如果未能解决你的问题,请参考以下文章
TypeScript 杂记九 《Integers Comparator》
TypeScript 杂记九 《Integers Comparator》