【问题标题】:How to type a composed function with spread arguments in Typescript?如何在 Typescript 中键入带有扩展参数的组合函数?
【发布时间】:2019-09-04 16:46:48
【问题描述】:

据我所知,展开运算符类型是数组。在这种情况下,fn(...args) 返回以下错误:

"不能调用类型缺少调用签名的表达式。类型 'never' 没有兼容的调用签名。”

我尝试了一些选项,但无法提出解决方案。

const callAll = (...fns: []) => (...args: []) => fns.forEach(fn => fn && fn(...args));

【问题讨论】:

    标签: typescript typescript-typings


    【解决方案1】:

    [] 实际上是一个空元组,因此该元组的一个项目是never 类型(即就打字稿而言永远不存在的东西)。如果您想要一个不想检查的项目数组,any[] 就是这样写的方式。

    const callAll = (...fns: any[]) => (...args: any[]) => fns.forEach(fn => fn && fn(...args))
    

    虽然这会通过编译器,但它的类型不是很安全,我们可以使用任何参数调用 callAll,打字稿不会抱怨(从编译器的角度来看,callAll(1,2,3) 是可以的)

    第一个改进是告诉 typescript 传递给 fn 的数组必须是函数数组:

    const callAll = (...fns: Array<(...a: any[])=> any>) => (...args: any[]) => fns.forEach(fn => fn && fn(...args));
    
    const composed = callAll(a => console.log("a " + a), b => console.log("b " + b))
    composed("arg");
    

    我使用了Array&lt;T&gt; 语法而不是T[],这两个表示相同的类型,但是由于T 是一个函数签名((...a: any[])=&gt; any),所以这个语法更容易阅读。函数签名将允许任何函数进入数组,而不以任何方式关联它们。

    虽然有所改进,但仍不完美。没有检查所有函数的参数是否匹配,并且这些参数是否与传入的参数匹配。

    我们可以做得更好,检查参数类型是否匹配,参数类型是否也匹配。为此,我们需要将泛型类型参数添加到我们的函数中。 P 将代表参数的类型。这将让我们将参数类型转发给返回的函数,并强制所有函数必须具有相同的参数类型:

    const callAll = <P extends any[]>(...fns: Array<(...a: P)=> void>) => (...args: P) => fns.forEach(fn => fn && fn(...args));
    
    const composed = callAll(
        (a: string) => console.log("a " + a), // only first one must specify param types
        b => console.log("b " + b)
    ) // b is inferred as string
    composed("arg");
    composed(1); //error must be strings
    
    const composedBad = callAll(
        (a: string) => console.log("a " + a), 
        (b: number) => console.log("b " + b) // error parametr types don't match
    )
    

    【讨论】:

      猜你喜欢
      • 2016-10-05
      • 2017-04-18
      • 2012-09-29
      • 2022-01-25
      • 2021-11-17
      • 2018-08-23
      • 2013-09-30
      • 2021-05-13
      • 1970-01-01
      相关资源
      最近更新 更多