简体   繁体   English

"lodash流函数应该如何在打字稿中输入?"

[英]How should the lodash flow function be typed in typescript?

lodash.flow<\/code> combines two or more functions. lodash.flow<\/code>结合了两个或多个功能。

lodash.flow(double, addTwo)<\/code> would return a function the would double and add two. lodash.flow(double, addTwo)<\/code>将返回一个函数,该函数将加倍并加两个。 How should this function be typed in typescript (the current definition just returns Function)?这个函数应该如何在打字稿中输入(当前定义只返回函数)?

declare function flow<In, Intermediate, Out>(f1: (a1: In) => Intermediate, f2: (a1: Intermediate) => Out): (a1: In)=> Out<\/code> works for two functions with the first having one input argument. declare function flow<In, Intermediate, Out>(f1: (a1: In) => Intermediate, f2: (a1: Intermediate) => Out): (a1: In)=> Out<\/code>适用于两个函数,第一个具有一个输入参数。 I'm not sure how to extend the definition to work in all cases.我不确定如何扩展定义以适用于所有情况。

My attempt can support mulitple functions if called like this:如果这样调用,我的尝试可以支持多个函数:

lodash.flow(f1, lodash.flow(f2, f3))<\/code>

but am looking for但我正在寻找

lodash.flow(f1, f2, f3)<\/code>

"

I don't believe you can write that definition. 我不相信您可以编写该定义。

If we look at the lodash type declaration file they don't try to express that relationship. 如果我们查看lodash类型声明文件,它们不会尝试表达这种关系。

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

But that alone isn't reason enough to discount the possibility. 但是,仅凭这一点还不足以打消这种可能性。 The authors may have just overlooked something, so let's keep thinking about it. 作者可能只是忽略了一些东西,所以让我们继续考虑一下。

The relationship between an individual chain of functions is something you can represent. 您可以表示单个功能链之间的关系。 You've done so in your example above. 在上面的示例中,您已经这样做了。 You could create manual versions of that same idea for several lengths of parameters but that's because you're setting up a situation where the length of the chain is known and you can grant individual type information. 您可以为多个参数长度创建相同想法的手动版本,但这是因为您正在设置一种情况,其中链的长度是已知的,并且您可以授予单个类型信息。

If we are to handle the case of variable length parameters, we must treat the parameters as a Collection . 如果要处理可变长度参数的情况,则必须将参数视为Collection Because all variables must have a single (though possibly parameterized) type so too must this collection object. 因为所有变量都必须具有单个(尽管可能是参数化的)类型,所以此集合对象也必须具有单个类型。 However, the types of the various functions do not align. 但是,各种功能的类型不一致。 (param:A) => B is not the same type as (param:B) => C and cannot be stored in the same well typed container (barring union types but those won't scale either). (param:A) => B(param:B) => C ,并且不能存储在相同类型的容器中(限制并集类型,但它们也不会缩放)。

In situations where you want to retain type information on a list of parameters like this you usually define the composition function on two parameters and apply it across a number of functions. 在要在这样的参数列表上保留类型信息的情况下,通常可以在两个参数上定义组合函数,并将其应用于多个函数。 This is how type information is retained in promises, for example. 例如,这就是类型信息在Promise中保留的方式。 For this to work you still need to have each individual parameter spelled out. 为此,您仍然需要阐明每个参数。 It just makes it so by the end you've got the proper output type. 这样一来,最终您就拥有了正确的输出类型。 That said, in most cases this is what you want so it's all good. 就是说,在大多数情况下这就是您想要的,这一切都很好。

If lodash were written in a well typed functional language, that flow function probably wouldn't exist. 如果lodash用一种类型正确的函数式语言编写,则该流函数可能将不存在。 I imagine it would instead have been written as a piped composition object. 我想它会被改写为管道组成对象。

UPDATE : What do I mean when I say a "piped composition object"? 更新 :我说“管道合成对象”是什么意思? Something like this, perhaps: 大概是这样的:

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

here's a way to kind of do it using conditional types<\/a> :这是一种使用条件类型<\/a>的方法:

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;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM