【问题标题】:Typescript - Generic Type Variables: Type 'T' is not assignable to type 'T'. Two different types exists with this name exist but they are unrelatedTypescript - 通用类型变量:类型“T”不可分配给类型“T”。存在具有此名称的两种不同类型,但它们不相关
【发布时间】:2019-02-21 23:06:27
【问题描述】:

使用打字稿 3.0+。请参阅以下涉及泛型类型变量的简单设置:

abstract class BaseClass {
  public abstract merge<T>(model?: T): T;
}

class MyClass extends BaseClass {

  public Value: string;

  public merge<MyClass>(model?: MyClass): MyClass {
    this.Value += model.Value; // <--Property 'Value' does not exist on type 'MyClass'

    return this; // <--Type 'this' is not assignable to type 'MyClass'.
                 //    Type 'MyClass' is not assignable to type 'MyClass'.
                 //    Two different types with this name exist, but they are unrelated.
  }
}

我注意到 Typescript 编译器描述的错误,但这些错误对我来说没有意义。为什么这是错误的?


更新

我现在明白,MyClass 中合并方法上方的原始代码定义了一个与“MyClass”同名的新泛型类型变量,这解释了错误。所以我做出如下所示的改变。这仍然会产生错误,我在merge方法上方对此进行了评论:

abstract class BaseClass {
  public abstract merge<T>(model?: T): T;
}

class MyClass extends BaseClass {

  public Value: string;

/*
Property 'merge' in type 'MyClass' is not assignable to the same property in base type 'BaseClass'.
  Type '(model?: MyClass) => MyClass' is not assignable to type '<T>(model?: T) => T'.
    Types of parameters 'model' and 'model' are incompatible.
      Type 'T' is not assignable to type 'MyClass'.
*/
  public merge(model?: MyClass): MyClass {
    this.Value += model.Value;

    return this;
  }
}

为什么我不能在这里使用 MyClass 作为变量类型?事实上,我似乎无法用任何其他可以使其工作的类型(例如字符串、数字、另一个类)来替换它。

即使我尝试将 T 定义为扩展 BaseClass 的类型:

abstract class BaseClass {
  public abstract merge<T extends BaseClass>(model?: T): T;
}

这仍然会在 MyClass 中产生相同的错误。请注意,这适用于 TypeScript 2.2.1。我只注意到这不适用于任何 TypeScript 2.4+ 版本。

【问题讨论】:

    标签: typescript generics contravariance typescript3.0


    【解决方案1】:

    public merge&lt;MyClass&gt; 中的&lt;MyClass&gt; 引入了另一种类型(泛型),它与class MyClass 不同,但名称相同。对此泛型类型一无所知,因此您会收到错误 Property 'Value' does not exist on type 'MyClass'

    class MyClass 类型的thismodel 是泛型类型。

    如果您的基类将方法定义为merge&lt;T&gt;(model?: T): T,则派生类需要使用相同的定义。您在基类中承诺您将处理任何参数(没有任何限制的通用 T),您不能在派生类中将其仅限制为 MyClass

    【讨论】:

    • 如果我做了你建议的改变,那么我会得到一个不同的错误:Property 'merge' in type 'MyClass' is not assignable to the same property in base type 'BaseClass'. Type '(model?: MyClass) =&gt; MyClass' is not assignable to type '&lt;T&gt;(model?: T) =&gt; T'. Types of parameters 'model' and 'model' are incompatible. Type 'T' is not assignable to type 'MyClass'.
    • 我错过了问题的 T 部分。我会尝试更新答案。
    • 如果派生类也需要使用泛型变量类型,那么如何使用强类型参数和返回值呢?这似乎没有用或不正确。我能够完成这项工作的唯一方法是将泛型变量类型提升到 BaseClass 中的类级别。但是说起来似乎很奇怪:class MyClass extends BaseClass&lt;MyClass&gt; {...
    • 我不确定我是否理解您想要实现的目标。也许你的基/派生层次设计是错误的?一旦您在 BaseClass 中承诺您可以与任何模型合并,您就不能在 MyClass 中收回承诺并说您只能与 MyClass 合并。
    • 你想要的与可能的相反。如果有人持有一个类型为 BaseClass 的变量,并且使用此变量尝试与不是 MyClass 的模型合并,会发生什么情况?参数需要逆变的这种语言无关的原因 - 派生类与基类相比永远不会限制参数,因为可以使用基类的接口调用方法。
    猜你喜欢
    • 2018-09-19
    • 2021-11-16
    • 1970-01-01
    • 2016-07-31
    • 2022-11-11
    • 2022-11-11
    • 2020-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多