typescript - 为什么在泛型上使用 InstanceType 是错误的

标签 typescript typescript-generics

为什么用InstanceType错了在泛型上?是协变的还是逆变的?

interface Ctor {
  new(): Instance;
}

interface Instance {
  print(): void;
}

function f1<T extends Ctor>(ctor: T) {
  // Error: Type 'Instance' is not assignable to Type 'InstanceType<T>'
  const ins: InstanceType<T> = new ctor();
  ins.print();
}

function f2(ctor: Ctor) {
  // No error
  const ins: InstanceType<Ctor> = new ctor();
  ins.print();
}

Playground Link

最佳答案

这是我认为的问题:Typescript 确定表达式的编译时类型 new ctor()通过查看 ctor 的类型(即 T ),检查 T必须有一个构造函数签名(它有),然后找到 T 的构造函数签名是什么返回。但是T可以是 Ctor 的任何子类型,所以它的构造函数签名可以返回 Instance 的任何子类型.
在这种情况下,编译器可以做两件合理的事情:

  • 要么发明一个新的类型变量(我们称之为 R extends Instance ),然后让表达式的类型 new ctor()R ,
  • 或者让表达式的类型为 Instance .

  • Typescript 做后者,也许是因为 Typescript 只有在你告诉它的情况下才会创建类型变量;它从不隐含地这样做。这使表达式的类型比赋值给 InstanceType<T> 所需的类型更弱。进行类型检查,因为 InstanceType<T>确实显式地创建了一个类型变量 R (在条件类型中使用 infer 子句),它可以是 Instance 的任意子类型.
    所以表达式的类型new ctor()Instance ,但赋值目标的类型注释(不是真的,但在某种意义上)是一个类型变量 R可以是 Instance 的任何子类型,因此存在类型错误。
    一个可能的解决方案是为返回类型显式创建一个类型变量,如下所示:
    function f1<R extends Instance, T extends {new(): R}>(ctor: T) {
      const ins: R = new ctor();
      ins.print();
    }
    
    也就是说,只有当您的函数处理 R 时才值得这样做。以其他一些能力,例如具有涉及 R 的返回类型.否则,您的代码使用 ins必须适用于 R 的任何实现包括 Instance本身,因此您不妨将其类型声明为 Instance反正。 (同样,如果您的函数不在其他任何地方使用 T,您不妨改为使用参数类型 Ctor)。

    关于typescript - 为什么在泛型上使用 InstanceType 是错误的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66405673/

    相关文章:

    javascript - 当对象类型不匹配时,对于泛型函数不会出现编译错误

    typescript - 动态 Typescript 对象属性

    typescript - 如何从泛型类访问静态变量?

    reactjs - Typescript:变量被分配了一个值但从未使用过,除非它被使用

    Angular APP_INITIALIZER

    javascript - 如何在 Typescript 和 React.js 中使用随机字段解析 JSON

    javascript - 将嵌套数组转换为单个数组

    javascript - 复杂 else if 梯子的替代方案

    typescript - 键在应该用于索引类型时却不能使用

    typescript - 如何推断具有多个泛型的 Typescript 可变参数元组类型?