可以使用不同的约束子类型来实例化函数
Posted
技术标签:
【中文标题】可以使用不同的约束子类型来实例化函数【英文标题】:Function could be instantiated with a different subtype of constraint 【发布时间】:2020-03-27 14:44:29 【问题描述】: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
【问题讨论】:
this answer 非常详细地介绍了此错误消息。看看你能不能用它解决你的问题。 【参考方案1】:问题在于F
上的约束(...args: any[]) => void
可以通过许多您可能会感到惊讶的类型来满足,并且您返回的函数将不能分配给这些类型。例如:
debounce(() => "oopsie", 1000)().toUpperCase(); // okay at compile time, typeError at runtime
这里,函数类型F
返回一个string
值;这可以分配给void
-返回函数类型,如explained in the FAQ。但是debounce()
当然不会返回一个string
-returning函数,所以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
不同。
这里的解决方法是使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)
)
编译没有错误。好的,希望有帮助;祝你好运!
Link to code
【讨论】:
但是你将如何扩大它以允许其他返回类型?以上是关于可以使用不同的约束子类型来实例化函数的主要内容,如果未能解决你的问题,请参考以下文章
类型“XX”不可分配给类型“YY”。 'XX' 可分配给'YY' 类型的约束,但'YY' 可以被实例化