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

标签 typescript generics types subtyping

我在玩使用 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'.

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

最佳答案

“问题”是这样的: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
  • logFn((a, b) => a + b)
  • logFn((a, b, c) => c)

  • 但是如果你回顾我给出的例子,内部定义为:
    return (a, b) => fn(a, b);
    

    所以选项 2. 会在这里抛出一个错误,这就是 typescript 警告你的原因。
    logFn<T extends (...args: any[]) => any>(fn: T): T
    

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

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

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

    关于typescript - 泛型函数子类型约束错误和混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58209952/

    相关文章:

    haskell - Template Haskell 中准引号内的类型检查

    typescript - 装饰器不支持函数调用,但调用了 'AngularFireModule'

    typescript - 如何处理可能是多种类型之一的变量

    c# - 方法中的 new()

    Java 8 Comparator比较静态函数

    C# 将对象列表中的对象转换为类型返回左手签名必须是变量错误

    angular typescript - 何时指定参数类型

    javascript - 调用 axios 时出现 typescript 错误 - 没有重载匹配此调用

    c# - 使用配置文件中的字符串来初始化泛型

    c++ - 类型衰减——它是什么以及为什么会存在?