# 17-柯里化1

# 题目描述

在此挑战中建议使用 TypeScript 4.0

Currying (opens new window) 是一种将带有多个参数的函数转换为每个带有一个参数的函数序列的技术。

例如:

const add = (a: number, b: number) => a + b;
const three = add(1, 2);

const curriedAdd = Currying(add);
const five = curriedAdd(2)(3);

传递给 Currying 的函数可能有多个参数,您需要正确键入它。

在此挑战中,curried 函数一次仅接受一个参数。分配完所有参数后,它应返回其结果。

# 分析

这个题目并不算复杂,做了那么多中等难度题目的,仔细分析下应该好解决的。

这个题目本质是定义一个函数类型 Currying,入参是一个函数 F,返回值是一个新的函数 R。

这里的返回新的函数,其实就是去除了 F 中第一个入参后剩余入参和 F 的返回值组成的新的函数。

对于函数的入参和返回值匹配,可以说是基操了,这里不做解释。

这题稍微麻烦的是新的函数 R,这个函数的定义,如果入参的数量为 0,那么返回 F 的返回值,否则继续做柯里化。

# 题解

// 由于需要递归,所以需要单独伶出来一个类型来做递归
type CurriedFn<Fn> =
  // 匹配入参 P 和 返回值 R
  Fn extends (...args: infer P) => infer R
    ? // 匹配第一个参数 F 和其他参数 Other
      P extends [infer F, ...infer Other]
      ? // 如果入参不为空,返回新的函数,入参就是第一个参数 F
        (arg: F) => // 判断剩余参数为空
        Other extends []
          ? // 如果剩余参数为空,那么就是返回值本身
            R
          : // 否则还需要进行一次柯里化,也可以看出来
            // 递归的过程中,已经排除了入参为空的情况
            CurriedFn<(...args: Other) => R>
      : // 入参为空,就返回函数自身,应对初始入参为空的情况
        Fn
    : never;

declare function Currying<F>(fn: F): CurriedFn<F>;

这个过程不好用语言描述,可以在脑海中过几遍就好理解了。

# 知识点

  1. 函数入参、返回值匹配
  2. 递归处理嵌套问题。
Last Updated: 2023/5/16 06:00:28