如何创建一个具有类型化回调的函数,以确保所有回调参数都传递给它



给定一个接受带有类型化参数的回调的函数,我如何确保它不允许没有参数的函数。

我添加了一个代表我的问题的示例代码片段

function x(cb: (a: number) => any) {
cb(12)
}
x((a: number) => 1) // OK
x(() => 1) // OK
x((a: string) => 1) // Error: Argument of type '(x: string) => number' is not assignable to parameter of type '(a: number) => any'.

第二行应该会生成一个错误,因为它没有传递回调所需的完整参数列表

我想强制执行函数x的每次使用都应该在回调中具有原始函数签名中指定的所有参数

游乐场链接

TypeScript的一般行为是,可以有一个需要比所提供的更少参数的函数。例如,当您有一个onClick函数(e: MouseEvent) => void时,可以提供一个不使用e的函数。

因此,为了禁止() => 1,我们必须在这里变得棘手,因为这个函数可分配给(a: number) => any

解决方案

function x<T extends (a: number) => any>(cb: T & ([] extends Parameters<T> ? never : T)) {
cb(12)
}
x((a: number) => 1) // OK
x(() => 1) // Error: Argument of type '() => number' is not assignable to parameter of type 'never'.
x((a: string) => 1) // Error: Argument of type '(x: string) => number' is not assignable to parameter of type '(a: number) => any'.

解释

我使用一个泛型类型参数T来表示函数x的回调参数。我们说cb必须是T,但我们也强加了一个附加规则。我们需要检查回调的参数Parameters<T>。如果一个空数组[]可分配给这些参数([] extends Parameters<T>(,我们说cb必须是T & never

T & never是一个不可能的条件,它导致我们在您的第二个例子中得到带红色下划线的错误。这里T被推断为() => number,所以cb必须是never。因此,我们得到一个错误"em";类型为"((=>"的参数;"number"不可分配给"never"类型的参数">


您的示例函数x不返回任何内容,但它可以return cb(12)并根据回调cb的返回类型获得正确的返回类型。

function x<T extends (a: number) => any>(cb: T & ([] extends Parameters<T> ? never : T)): ReturnType<T> {
return cb(12)
}

TypeScript游乐场链接

最新更新