typescript实现curring,柯里化函数的类型标注

兰涛 lands

前言

最近我在封装一些工具方法,在封装到柯里化函数的时候,发现柯里化函数的 ts 类型标注十分困难。尝试了很多办法都没办法实现,使用 curry 生成的新函数能带提示的输入多个参数。

效果

最后取了一个择中的办法,柯里化函数本身传递两个参数fnargs,第一次调用传达一个函数和 N 和参数,生成新的函数 newFn,newFn 中接收一个后续参数,带类型提示。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* @type T代表传入函数的类型
* @type First代表第一次进入的参数
*/
type CurryFunc<T, First extends any[]> = T extends (
...args: infer Args
) => infer R
? // eslint-disable-next-line @typescript-eslint/no-unused-vars
Args extends [...First, infer Mid, ...infer Tail]
? (v: Mid) => CurryFunc<T, [...First, Mid]>
: R
: T;

/**
* 柯里化函数 可根据传入函数的类型自动推导
* @param fn 需要柯里化的函数
* @param rest 需要柯里化的函数的初始参数
* @returns 返回一个被柯里化的新函数或者 需要柯里化的函数的返回值
* @tip 由于ts类型限制的原因 无法在一个函数被柯里化后,再次多次传参!所以如果第二次传参需要使用多参数形式 需要使用@ts-ignore
* @example
* function add(a: number, b: number, c: number, d: number, e: number) {
* return a + b + c;
* }
* curry(add)(1)(2)(3)(4)(5);
* curry(add, 1)(2)(3)(4)(5);
* curry(add, 1, 2)(3)(4)(5);
* curry(add, 1, 2, 3)(4)(5);
* curry(add, 1, 2, 3, 4)(5);
* curry(add, 1, 2, 3, 4, 5);
*/

export function curry<T extends (...args: any[]) => any, First extends any[]>(
fn: T,
...rest: First
): CurryFunc<T, First> {
return function (...args: any[]): any {
const currentArgs = [...rest, ...args];
return currentArgs.length >= fn.length
? fn(...currentArgs)
: curry(fn, ...currentArgs);
} as CurryFunc<T, First>;
}

此处用到了 ts 中的 infer,infer 表示占位,一般用于后面想要继承传入类型的时候,使用了 infer 后 ts 会自动推导。

1
2
function f(params: infer P extends any): P;
f(123);

如上:我们定义函数 f,调用函数的时候传入的是 number,则 P 就是 number 类型。

  • 标题: typescript实现curring,柯里化函数的类型标注
  • 作者: 兰涛
  • 创建于 : 2023-07-04 16:21:23
  • 更新于 : 2024-01-26 09:52:55
  • 链接: https://lands.work/d37ea48/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
此页目录
typescript实现curring,柯里化函数的类型标注