给定一个接受带有类型化参数的回调的函数,我如何确保它不允许没有参数的函数。
我添加了一个代表我的问题的示例代码片段
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游乐场链接