【问题标题】:TypeScript: Catch variable signature of a function passed as argument in higher order functionTypeScript:捕获在高阶函数中作为参数传递的函数的变量签名
【发布时间】:2021-02-10 04:30:49
【问题描述】:

我希望高阶函数能够捕获传递函数的签名参数,该函数可以具有不同的签名。

我不知道这是否可行,但这是我的方法:

type FuncA = (a: string, b: number) => void
type FuncB = (a: string) => void

type Func = FuncA | FuncB

const a: FuncA = (a: string, b: number) => {
  console.log('FuncA')
}

const b: FuncB = (a: string) => {
  console.log('FuncB')
}

// My higher order function
const c = (func: Func) => {
  // do something here...
  return (...args: Parameters<typeof func>) => {
    func(...args) // Expected 2 arguments, but got 0 or more. ts(2556). An argument for 'a' was not provided.
  }
}

我的高阶函数c无法传递func的参数 似乎 TypeScript 无法区分 Func 类型的不同可能签名。

有人知道编写这种代码的模式吗?

谢谢!

【问题讨论】:

    标签: node.js typescript typescript-typings


    【解决方案1】:

    这是一个艰难的过程,因为对于extend 的函数,另一个函数并不完全符合您的想法。

    我们希望c 创建的函数要求参数与给定的函数相对应。所以我们使用generic来描述函数。

    const c = <F extends Func>(func: F) => {
      return (...args: Parameters<F>) => {
        func(...args); // still has error
      }
    }
    

    此时我们仍然有这个错误,但是当我们调用c 时,我们会得到一个具有正确参数的函数,这取决于我们是否给了它ab

    const cA = c(a); // type: (a: string, b: number) => void
    cA("", 0);
    
    const cB = c(b); // type: (a: string) => void
    cB("");
    

    至于错误,它与一个函数扩展另一个函数的含义有关。尝试将F extends Func 更改为F extends FuncAF extends FuncB 看看会发生什么。对于F extends FuncB,我们在c(a) 上得到一个错误,但是对于F extends FuncA,我们在c(b) 上没有得到一个错误。嗯?

    如果您从回调的角度来考虑它,那是有道理的。可以传递一个需要比预期更少的参数的函数,但不能传递一个需要更多参数的函数。但是我们是实现回调的人,所以这给我们带来了问题。如果我们使用没有参数的函数扩展 type Func,则来自 Parameters&lt;F&gt; 的空数组不足以调用任何一种类型。

    我们必须让我们的泛型依赖于参数。

    type AP = Parameters<FuncA> // type: [a: string, b: number]
    type BP = Parameters<FuncB> // type: [a: string]
    
    type Args = AP | BP;
    
    const c = <A extends Args>(func: (...args: A) => void) => {
      return (...args: A) => {
        func(...args) // no error
      }
    }
    

    Typescript Playground Link

    【讨论】:

      【解决方案2】:

      如果您认为装饰函数是任何函数,您可以这样做:

      const c = <T extends (...a: any) => any>(func: T) => {
        // do something here...
        return (...args: Parameters<typeof func>): ReturnType<T> => {
          return func(...args);
        }
      }
      

      调用它看起来像

      c<typeof a>(a)('a', 2)
      

      【讨论】:

        猜你喜欢
        • 2018-06-27
        • 1970-01-01
        • 1970-01-01
        • 2020-01-07
        • 1970-01-01
        • 2018-07-27
        • 2016-02-24
        • 1970-01-01
        • 2017-06-16
        相关资源
        最近更新 更多