无不兼容的操作数

huangapple go评论60阅读模式
英文:

No incompatible operands

问题

我希望以下的等式表达式失败:

```ts
class C1 {
    static readonly X = new C1;
}
class C2 {
    static readonly X = new C2;
}
C1.X === C2.X;

TypeScript没有报告任何错误。是否有选项可以引发错误,例如:

> Comparison between incompatible types: C1 and C2


<details>
<summary>英文:</summary>

I want the follow equality expression to fail:

```ts
class C1 {
    static readonly X = new C1;
}
class C2 {
    static readonly X = new C2;
}
C1.X === C2.X;

TypeScript does not report any error on it. Is there an option to cause an error such as:

> Comparison between incompatible types: C1 and C2

?

答案1

得分: 1

在TypeScript中,class实例类型,像所有类型一样,通常是按结构而不是名称进行比较。

给定

class C1 {
    static readonly X = new C1;
}
class C2 {
    static readonly X = new C2;
}

C1C2的实例类型除了类似对象外没有任何结构。它们没有任何成员(类构造函数的静态成员不是实例类型的成员)。因此,它们等同于空对象类型{},因此彼此等同。这意味着C1.XC2.X都是相同类型,C1.X === C2.X是允许的。空类已知会表现出“奇怪”的行为

如果您希望它们被视为不兼容的类型,您应该给它们不兼容的结构。最简单的方法是给它们不同类型的成员。也许它们可以分别具有不同字面类型name属性,如下所示:

class C1 {
  static readonly X = new C1;
  readonly name = "C1";
}
class C2 {
  static readonly X = new C2;
  readonly name = "C2";
}

C1.X === C2.X; // 错误!
// 这个比较似乎是不打算的,
// 因为类型'C1'和'C2'没有重叠。

通过将name属性设为readonly,编译器将从初始化程序中推断出字面类型,如"C1""C2",而不仅仅是string(这不会区分它们)。

另一种方法是给它们都添加privateprotected属性,这将使它们不兼容,即使它们具有相同的形状也会如此。也就是说,private/protected属性将使class实例类型表现出名称而不是结构性:

class C1 {
  static readonly X = new C1;
  private prop?: undefined;
}

class C2 {
  static readonly X = new C2;
  private prop?: undefined;
}

C1.X === C2.X; // 错误!
// 这个比较似乎是不打算的,
// 因为类型'C1'和'C2'没有重叠。

代码的在线演示链接

英文:

In TypeScript, class instance types, like all types, are (generally) compared structurally and not nominally.


Given

class C1 {
    static readonly X = new C1;
}
class C2 {
    static readonly X = new C2;
}

the instance types C1 and C2 have no structure apart from being object-like. They don't have any members (the static members of the class constructor are not members of the instance types) So they are equivalent to the empty object type {} and therefore to each other. That means C1.X and C2.X are both of the same type, and C1.X === C2.X will be allowed. Empty classes are known to behave "strangely".


If you want them to be considered incompatible types, you should give them incompatible structure. The easiest way to do that is to give them members of different types. Perhaps they can each have a name property of a distinct literal type, as shown here:

class C1 {
  static readonly X = new C1;
  readonly name = &quot;C1&quot;;
  // (property) C1.name: &quot;C1&quot;
}
class C2 {
  static readonly X = new C2;
  readonly name = &quot;C2&quot;;
  // (property) C2.name: &quot;C2&quot;
}

C1.X === C2.X; // error! 
// This comparison appears to be unintentional 
// because the types &#39;C1&#39; and &#39;C2&#39; have no overlap.

By making the name property readonly the compiler infers a literal type like &quot;C1&quot; or &quot;C2&quot; from the initializer instead of just string (which would not distinguish them).


Another way to do this is to give them both private or protected properties, which makes them incompatible even if they have the same shape. That is, private/protected properties will make a class instance type behave nominally instead of structurally:

class C1 {
  static readonly X = new C1;
  private prop?: undefined;

}
class C2 {
  static readonly X = new C2;
  private prop?: undefined;
}
C1.X === C2.X; // error! 
// This comparison appears to be unintentional 
// because the types &#39;C1&#39; and &#39;C2&#39; have no overlap.

Playground link to code

huangapple
  • 本文由 发表于 2023年6月22日 02:12:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76526076.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定