lodash flow 函数在 typescript 中应该怎么写?

How should the lodash flow function be typed in typescript?

lodash.flow 组合了两个或多个函数。

lodash.flow(double, addTwo) 将 return 函数加倍并加二。这个函数应该如何在打字稿中输入(当前定义只是 returns 函数)?

declare function flow<In, Intermediate, Out>(f1: (a1: In) => Intermediate, f2: (a1: Intermediate) => Out): (a1: In)=> Out 适用于两个函数,第一个函数有一个输入参数。我不确定如何扩展定义以适用于所有情况。

如果这样调用,我的尝试可以支持多个函数:

lodash.flow(f1, lodash.flow(f2, f3))

但我正在寻找

lodash.flow(f1, f2, f3)

我不相信你能写出那个定义。

如果我们看 the lodash type declaration file 他们不会试图表达这种关系。

interface LoDashStatic {
    flow<TResult extends Function>(...funcs: Function[]): TResult;
}

但仅凭这一点还不足以排除这种可能性。作者可能刚刚忽略了一些东西,所以让我们继续思考。

单个功能链之间的关系是您可以表示的。您已经在上面的示例中这样做了。您可以为多个长度的参数创建相同想法的手动版本,但那是因为您设置的情况是链的长度已知并且您可以授予单独的类型信息。

如果我们要处理可变长度参数的情况,我们必须将参数视为一个Collection。因为所有变量都必须有一个单一的(尽管可能是参数化的)类型,所以这个集合对象也必须有。但是,各种功能的类型并不一致。 (param:A) => B(param:B) => C 的类型不同,不能存储在同一个类型良好的容器中(禁止联合类型,但它们也不会扩展)。

在这样的情况下,您希望在参数列表中保留类型信息,您通常会在两个参数上定义组合函数,并将其应用于多个函数。例如,这就是在承诺中保留类型信息的方式。为此,您仍然需要详细说明每个单独的参数。它只是让你最终得到正确的输出类型。也就是说,在大多数情况下,这就是您想要的,所以一切都很好。

如果 lodash 是用类型良好的函数式语言编写的,那么流函数可能不会存在。我想它会被写成一个管道组合对象。

更新:我说 "piped composition object" 是什么意思?可能是这样的:

class FunctionComposer<T,V> {
    constructor(protected func: (param: T) => V) { }

    public compose<X>(newFunc: (param:V) => X) {
        return new FunctionComposer((x: T) => newFunc(this.func(x)));
    }
    public out() {
        return this.func;
    }
}

let composedFunc = new FunctionComposer((x: number) => x * 2)
    .compose(x => x.toString())
    .out();

// composedFunc has type (param:number) => string

这里有一种方法可以使用 conditional types:

const compose =
  <T1, T2>(f1: (p: T1) => T2) =>
  <T3>(f2: (p: T2) => T3) =>
  (p: T1) =>
    f2(f1(p));

const flow = <T1, T2, T3 = "♘", T4 = "♘">(
  f0: (p: T1) => T2,
  ...f: [] | [(p: T2) => T3] | [(p: T2) => T3, (p: T3) => T4]
): ((p: T1) => T3 extends "♘" ? T2 : T4 extends "♘" ? T3 : T4) => {
  if (f[1]) {
    return compose(compose(f0)(f[0]!))(f[1]) as any;
  }

  if (f[0]) {
    return compose(f0)(f[0]) as any;
  }

  return f0 as any;
};

在此示例中,flow 最多支持 3 个参数,但可以根据需要扩展到任意数量。