TypeScript 如何做函数柯里化类型

在写前端代码时,你有没有过这种困扰:明明函数逻辑没问题,却总因为参数类型错了,导致编辑器飘红?尤其是用 TypeScript 做项目时,想让类型既能灵活适配不同场景,又不丢失严谨性,常常有点难。而函数柯里化,就是帮你解决这个问题的小工具——它把接收多个参数的函数,拆成一个个只接收单个参数的函数,直到传完所有参数再执行逻辑。而在 TypeScript 里,给柯里化函数加类型,能让代码既灵活又安全。

先搞懂“普通柯里化”的生活化例子

先不说复杂的代码,用点奶茶的场景就能明白。假设你点奶茶需要三步:选奶茶(珍珠奶茶/柠檬茶)、选糖度(三分糖/全糖)、选冰度(去冰/少冰)。如果用普通函数写,可能是一个接收三个参数的函数:orderDrink("珍珠奶茶", "三分糖", "去冰")。而柯里化之后,就变成了先选奶茶:const pickMilkTea = curry(orderDrink)("珍珠奶茶"),再选糖度:const pickSugar = pickMilkTea("三分糖"),最后传冰度就出结果了。

TypeScript 如何做函数柯里化类型

这个逻辑用到 TypeScript 里,核心就是把多参数的函数类型,拆成“传一个参数返回新函数”的类型。比如普通函数的类型是(a: T, b: U) => V,柯里化后就变成(a: T) => (b: U) => V——这就是柯里化类型的基础。

给柯里化函数加类型的小技巧

在 TypeScript 里,要写柯里化类型,不用自己硬啃复杂的泛型,用内置的Parameters和ReturnType就能轻松搞定。先看个简单的例子:假设我们有一个计算购物总价的函数,普通类型是(price: number, count: number, discount: number) => number,柯里化后,它的类型应该是先接收price,再接收count,最后接收discount,返回总价。

具体怎么写类型呢?第一步,用Parameters拿到原函数的参数类型数组,也就是[number, number, number];第二步,用ReturnType拿到原函数的返回类型number;第三步,把参数数组“拆成单个传参”,也就是从[P, C, D]变成(p: P) => (c: C) => (d: D) => ReturnType。这样写出来的类型,既能适配原函数的参数,又保留了柯里化的灵活性。

举个实际能用的例子:如果我们想做一个“固定折扣的总价计算器”,可以先把折扣传进去,得到一个新的柯里化函数。用带类型的柯里化,就不会写错参数——比如你要是不小心把count写成了字符串,编辑器会直接报错,不会等到运行时才出问题。

避免踩坑的小提醒

实际用的时候,有个小坑要注意:如果原函数的参数有可选参数,柯里化类型别硬套Parameters。比如原函数是(a: number, b?: string) => void,Parameters拿到的是[number, string?],这时候拆类型的话,要把可选参数的?保留,不然会让新函数的参数变成必填,用起来就麻烦了。

另外,别为了柯里化而柯里化。如果你的函数本来就只需要一次传完参数,硬拆成柯里化反而会让代码变复杂。只有当你需要“先传部分参数,后面再补”的场景,比如用户登录时先填手机号,后面再填验证码,这时候用带类型的柯里化才最实用。

总的来说,TypeScript 做函数柯里化类型,核心就是把多参数的函数类型拆成嵌套的单参数函数类型,用简单的内置类型工具就能搞定,既保留了柯里化的灵活性,又不会丢了 TypeScript 的类型安全,刚好适合前端项目里那些需要灵活适配的场景。

上一篇 Swift编程语言核心特性与应用场景科普