首页 > 解决方案 > TypeScript:捕获在高阶函数中作为参数传递的函数的变量签名

问题描述

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

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

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 无法区分 type 的不同可能签名的参数Func

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

谢谢 !

标签: node.jstypescripttypescript-typings

解决方案


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

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

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

在这一点上,我们仍然有这个错误,但是当我们调用 时c,我们会得到一个函数,该函数根据我们是否给出了正确的a参数b

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

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

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

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

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

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

打字稿游乐场链接


推荐阅读