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

Generic Function Subtype Constraint Error and Confusion

我正在考虑使用 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'.

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

"problem"是这样的:T extends (...args: any[]) => any

如果你看到下面的版本,它更直观:

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

您将看到错误保留

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

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

  1. logFn((a, b) => a + b)
  2. logFn((a, b, c) => c)

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

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

所以选项 2. 会在此处抛出错误,这就是打字稿警告您的原因。

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

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

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

您的变通方法很好的原因是,通过添加 (...args: Parameters<T>) => ReturnType<T>,您告诉编译器参数和 return 类型必须与传递的函数匹配,而不是 T可以是任何其他函数定义