【问题标题】:Currying in TypeScript在 TypeScript 中柯里化
【发布时间】:2022-11-25 04:04:41
【问题描述】:

我正在尝试在 TypeScript 中定义柯里化函数的类型。 JavaScript版本如下:

function curry1(fn) {
  return (x) => (fn.length === 1 ? fn(x) : curry1(fn.bind(undefined, x)));
}

这非常有效——将 curry1 应用于函数会生成一元函数。如果你用一个参数调用那个函数,它会产生另一个一元函数,当用一个参数调用它时会产生另一个一元函数,等等,直到所有参数都被提供,在这种情况下它会产生一个结果。下面的 Currying f1 产生一个等同于 (a)=>(b)=>(c)=>result 的函数。

const make3 = (a, b, c) => `${a}:${b}:${c}`;

const f1 = curry1(make3);
const f2 = f1('A');
const f3 = f2(2);
const f4 = f3('Z');

console.log(f4);  // A:2:Z

我定义了一个通用的 CURRY1 类型,它本质上返回一个函数,该函数将产生一个结果(如果给定一元函数)或一个少一个参数的柯里化函数(如果给定一个有两个或更多参数的函数)。

type CURRY1<P extends any[], R> = P extends [infer H]
  ? (arg: H) => R // only 1 arg?
  : P extends [infer H0, infer H1, ...infer T] // 2 or more args?
  ? (arg: H0) => CURRY1<[H1, ...T], R>
  : never;

接着

function curry1<P extends any[], R>(fn: (...args: P) => R): CURRY1<P, R> {
  return (x: any): any => (fn.length === 1 ? fn(x) : curry1(fn.bind(undefined, x)));
}

如果我写

const make3 = (a: string, b: number, c: string): string => `${a}:${b}:${c}`;

并写入f1 = curry1(make3) VSCode 正确显示f1 的类型是(arg: string) =&gt; (arg: number) =&gt; (arg: string) =&gt; string。但是,TypeScript 反对,说 Type '(x: any) =&gt; any' is not assignable to type 'CURRY1&lt;P, R&gt;' ts(2322)。如果我在 return 之前添加一个 // @ts-ignore 行,代码就可以完美运行。但是我怎样才能避免出现这个错误呢?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    一种任何比您定义的类型更通用咖喱 1<P, R>,您可以对您的类型进行显式类型转换 as CURRY1&lt;P, R&gt;

    function curry1<P extends any[], R>(fn: (...args: P) => R): CURRY1<P, R> {
      return (x: any): any => fn.length === 1 ? fn(x) as CURRY1<P, R>: 
                              curry1(fn.bind(undefined, x))) as CURRY1<P, R>;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-05-26
      • 2016-01-01
      • 2011-08-18
      • 1970-01-01
      • 1970-01-01
      • 2011-11-02
      • 1970-01-01
      • 2021-04-04
      • 2015-08-17
      相关资源
      最近更新 更多