泛型函数子类型约束错误和混淆

Posted

技术标签:

【中文标题】泛型函数子类型约束错误和混淆【英文标题】:Generic Function Subtype Constraint Error and Confusion 【发布时间】:2020-02-01 05:32:43 【问题描述】:

我在玩使用 TypeScript 的简单包装函数的想法。我最终得到了以下内容:

export function logFn<T extends (...args: any[]) => any>(
  fn: T,
): (...args: Parameters<T>) => ReturnType<T>  
  const log = (...args: Parameters<T>): ReturnType<T> => 
    console.log('log')
    return fn(...args)
  
  return log

这行得通,编译器很高兴。我的问题是关于我最初的尝试,看起来更像这样

export function logFn<T extends (...args: any[]) => any>(
  fn: T,
): T  
  const log: T = (...args) => 
    console.log('log')
    return fn(...args)
  
  return log

这在log 变量声明中给了我一个错误:

Type '(...args: any[]) => any' is not assignable to type 'T'.
  '(...args: any[]) => any' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '(...args: any[]) => any'.

似乎存在一些我无法完全理解的子类型关系约束(这个错误也没有给我带来太多好处)。希望对这些东西有更好精神理解的人能给我一个体面的解释,这样我就不会对这种行为感到困惑(我确信这是正确的)。

【问题讨论】:

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

“问题”是这样的:T extends (...args: any[]) =&gt; any

如果您看到以下版本,它会更直观:

export function logFn<T extends (...args: any[]) => any>(fn: T): T 
  return (a, b) => fn(a, b);

你会看到错误保持

类型 '(a: any, b: any) => any' 不能分配给类型 'T'。 '(a: any, b: any) => any' 可分配给类型 'T' 的约束,但 'T' 可以用不同的约束子类型 '(...args: any[]) = > 任何'。

T extends (...args: any[]) =&gt; any 而言,以下两项均有效

    logFn((a, b) =&gt; a + b) logFn((a, b, c) =&gt; c)

但是如果你再参考我给出的例子,内部定义为:

return (a, b) => fn(a, b);

所以选项 2. 会在这里抛出一个错误,这就是 typescript 警告你的原因。

logFn<T extends (...args: any[]) => any>(fn: T): T

我们将接收T 类型并返回T 类型。 return (a, b) =&gt; fn(a, b); 是一个有效的返回类型,它确实扩展了 (...args: any[]) =&gt; any 但你如何确定传递给 fn (T) 的值与该签名匹配? (即它可能是(...args: any[]) =&gt; any 的另一个不兼容子类型)

不确定我是否解释得足够好,但这是我的理解

您的解决方法很好的原因是,通过添加 (...args: Parameters&lt;T&gt;) =&gt; ReturnType&lt;T&gt;,您告诉编译器参数和返回类型必须与传递函数的参数和返回类型匹配,而不是 T,它可能是任何其他函数定义

【讨论】:

以上是关于泛型函数子类型约束错误和混淆的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin泛型 ① ( 泛型类 | 泛型参数 | 泛型函数 | 多泛型参数 | 泛型类型约束 )

泛型约束-swift

Kotlin泛型总结 ★ ( 泛型类 | 泛型参数 | 泛型函数 | 多泛型参数 | 泛型类型约束 | 可变参数结合泛型 | out 协变 | in 逆变 | reified 检查泛型参数类型 )

Swift参数及泛型参数参考!

请教一个unity有关于泛型参数的问题

C#的泛型的类型参数可以有带参数的构造函数的约束方式吗?