可以使用不同的约束子类型来实例化函数

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 Freturn ... as any

【问题讨论】:

this answer 非常详细地介绍了此错误消息。看看你能不能用它解决你的问题。 【参考方案1】:

问题在于F 上的约束(...args: any[]) =&gt; 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 类型将是一个函数类型()=&gt;void,带有一个额外的prop 属性。但同样,debounce() 不会返回带有这个额外的prop 属性的函数,因此debounce() 的返回类型再次与传入的F 不同。


这里的解决方法是使debounce() 仅通用到足以代表您实际在做什么。返回的函数将采用与传入函数相同的参数列表,因此我们需要参数列表是通用的。并且返回的函数肯定会返回 void 并且不会有额外的属性。所以只有实参列表需要一个类型参数(比如A),输入和输出函数的类型都是(...args: A) =&gt; 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

【讨论】:

但是你将如何扩大它以允许其他返回类型?

以上是关于可以使用不同的约束子类型来实例化函数的主要内容,如果未能解决你的问题,请参考以下文章

C# 如何根据指定变量来实例化对象?

类型“XX”不可分配给类型“YY”。 'XX' 可分配给'YY' 类型的约束,但'YY' 可以被实例化

我如何在函数体中使用通用类型

Custom AppComponentFactory无法实例化应用程序

C# 泛型类型参数的约束

C# 泛型类 构造方法中实例化T