我有一个类
Base
和一个继承自它的类 Derived
。 Base
有一个方法,将 Derived
作为参数并将 this
与其进行比较:
class Base {
foo(bar: Derived): void {
if(this === bar){
return;
}
//Do stuff
}
}
class Derived extends Base {
baz(): void {}
}
当我尝试编译它时,出现此错误:
error TS2367: This comparison appears to be unintentional because the types
'this' and 'Derived' have no overlap.
3 if(this === bar){
~~~~~~~~~~~~
我不明白为什么会出现此错误,
this
和Derived
都是Base
类型,所以它们do有重叠。如果我执行 const x = new Derived(); x.foo(x);
,它将进入 if
块,因此比较并非像编译器认为的那样毫无用处。
有趣的是,如果我删除
baz()
方法,使 Derived
具有空主体,错误就会消失(但这并不能解决我的问题,因为拥有空主体的类没有多大意义)。
为什么会出现此错误以及如何修复它?
错误消息的措辞可能具有误导性。将“无重叠”解释为不可能同时具有
this
类型和 Derived
类型的值是合理的,这显然是不正确的。错误消息曾经更糟糕,并说“这种比较总是false
”而不是“这似乎是无意的”。这已更改,请参阅 microsoft/TypeScript#27910,但关于“无重叠”的困惑仍然存在,人们已经针对它提出了问题,例如 microsoft/TypeScript#60583 和 microsoft/TypeScript#44645 和 microsoft/ TypeScript#37155。其中一些被归类为错误,但通常当 TS 团队给出解释时,错误的存在不是错误,但消息可以改进。
实际发生的情况是,TypeScript 有各种启发式方法来确定像
===
这样的比较运算符的使用可能是有意的还是不太可能是有意的。初步近似,规则是:如果 expr1 === expr2
的类型与 expr1
的类型兼容,则允许 expr2
,反之亦然。 “兼容”在这里意味着“可分配给”或“子类型”或“缩小范围”。细节并不是特别重要。在您的情况下,您不能将
this
分配给
Derived
类型的值,也不能将
bar
分配给
this
类型的值,因此两者都不能分配给另一个。因此 TypeScript 认为这表明您的比较可能是无意的。在类似的情况下,开发人员会很高兴收到该错误消息,因为他们确实写了错误的东西。正如microsoft/TypeScript#44645 的评论中提到的:
这些检查,当我们稍微收紧它们时,我们就会在实际代码中发现大量实际错误。比较的一侧与另一侧的超类型。 正如你所说,使用
===
可能会犯各种各样的错误,这些错误并非“可证明”总是错误的,但不太可能是故意的。在奇怪的代码中发出少量误报以在糟糕的代码中获得真阳性是所有类型检查器有意做出的权衡。在 TypeScript 将您的比较标记为可能无意的但您确实是这么想的情况下,您可以扩大
this
和Derived
都是
Base
类型。因此,将任一侧加宽到
Base
,错误就会消失:
if (this as Base === bar) { }
if (this === bar as Base) { }
最简单的方法是使用 类型断言来扩大,但由于类型断言也可能不安全地缩小范围,您可能更愿意避免或用更安全的东西来补充它:
const thisBase: Base = this; if (thisBase === bar) { }
if (this satisfies Base as Base === bar) { }
Playground 代码链接