TypeScript拒绝编译debounce
函数,因为包装函数的类型有问题:
export function debounce<F extends ((...args: any[]) => void)>(fn: F, timeout: number): F {
let timer: NodeJS.Timeout | undefined
// Problem here, TypeScript complains it's not the same function as F
return ((...args: any[]) => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => fn(...args), timeout)
})
}
错误:
Type '(...args: any[]) => void' is not assignable to type 'F'.
'(...args: any[]) => void' is assignable to the constraint of type 'F', but 'F' could be instantiated with a different subtype of constraint '(...args: any[]) => void'.ts(2322)
该如何解决?没有强制类型转换return ... as F
或return ... as any
答案 0 :(得分:3)
问题在于,(...args: any[]) => void
上的约束F
可以满足许多您可能会感到惊讶的类型的要求,并且您返回的函数将无法分配给此类类型。例如:
debounce(() => "oopsie", 1000)().toUpperCase(); // okay at compile time, typeError at runtime
此处,函数类型F
返回一个string
值;这可以分配给void
返回函数类型,例如explained in the FAQ。但是当然debounce()
不会返回返回string
的函数,因此debounce()
的返回类型与传入的F
不同。
也:
function foo() { };
foo.prop = 123; // property declaration
debounce(foo, 1000).prop.toFixed(); // okay at compile time, TypeError at runtime
在这种情况下,我们有一个带有property declared on it的函数。因此,这里的F
类型将是具有附加()=>void
属性的函数类型prop
。但是同样,debounce()
不会返回带有此额外prop
属性的函数,因此debounce()
的返回类型与传入的F
也不相同。< / p>
这里的解决方法是使debounce()
仅通用到足以代表您实际在做什么。返回的函数将采用与传入函数相同的参数列表,因此我们需要参数列表是通用的。并且返回的函数肯定会返回void
,并且不会在其上具有额外的属性。因此,只有参数列表需要类型参数(例如A
),输入和输出函数的类型均为(...args: A) => void
:
export function debounce<A extends any[]>(
fn: (...args: A) => void,
timeout: number
): (...args: A) => void {
let timer: NodeJS.Timeout | undefined
return ((...args: A) => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => fn(...args), timeout)
})
}
该编译没有错误。好的,希望能有所帮助;祝你好运!