代码之家  ›  专栏  ›  技术社区  ›  Donald Duck user7392049

这种比较似乎是无意的,因为类型“This”和“Derived”没有重叠

  •  1
  • Donald Duck user7392049  · 技术社区  · 8 月前

    我有课 Base 以及一个班级 Derived 这是从它继承下来的。 基地 有一个方法需要 衍生 作为参数并进行比较 this 对于它:

    class Base {
        foo(bar: Derived): void {
            if(this === bar){
                return;
            }
            //Do stuff
        }
    }
    
    class Derived extends Base {
        baz(): void {}
    }
    

    Playground link

    当我尝试编译它时,我得到了这个错误:

    error TS2367: This comparison appears to be unintentional because the types
     'this' and 'Derived' have no overlap.
    
    3         if(this === bar){
                 ~~~~~~~~~~~~
    

    我不明白为什么我会犯这个错误, 衍生 两者都是类型 基地 所以他们 有重叠。如果我这样做 const x = new Derived(); x.foo(x); 它将进入 if 块,因此比较并不像编译器认为的那样无用。

    有趣的是,如果我删除 baz() 方法,以便 衍生 如果一个类的主体是空的,错误就会消失(但这并不能解决我的问题,因为一个类没有多大意义)。

    为什么我会遇到这个错误,我该如何修复它?

    1 回复  |  直到 8 月前
        1
  •  1
  •   jcalz    8 月前

    错误消息的措辞可能具有误导性。将“无重叠”解释为不可能同时具有两种类型的值是合理的 this 类型 Derived ,这显然不是真的。错误信息曾经更糟糕,说“这种比较总是 false “而不是”这似乎是无意的“。已更改,请参阅 microsoft/TypeScript#27910 ,但关于“没有重叠”的困惑仍然存在,人们已经提出了反对它的问题,比如 microsoft/TypeScript#60583 microsoft/TypeScript#44645 microsoft/TypeScript#37155 其中一些被归类为bug,但通常当TS团队给出解释时,错误的存在不是bug,而是 消息 可以改进。

    实际情况是,TypeScript有各种启发式方法来确定是否使用比较运算符,如 === 很可能是有意的,也不太可能是故意的。第一个近似值是: expr1 === expr2 如果类型为 expr1 compatible with 类型 expr2 反之亦然。这里的“兼容”是指“可分配给”或“的子类型”或“缩小”。细节并不重要。

    就你的情况而言,你不能分配 为类型的值 衍生 ,也不能分配 bar 为类型的值 ,因此两者都不能分配给另一个。所以TypeScript认为这表明你的比较可能是无意的。在类似的情况下,开发人员很乐意收到错误消息,因为他们确实写错了东西。正如前文所述 a comment of microsoft/TypeScript#44645 :

    当我们稍微收紧这些检查时,我们会在实际代码中发现大量实际错误。

    你可能会犯各种各样的错误 === 这些不是 可证明的 总是假的,但不太可能是故意的。在奇怪的代码中发出少量误报,在糟糕的代码中得到真阳性,这是所有类型检查器故意做出的权衡。

    如果TypeScript将你的比较标记为可能是无意的,但你确实是认真的,你可以 拓宽 将一方与另一方的超类型进行比较。正如你所说, 衍生 两者都是类型 Base 因此,请将两侧拓宽至 基地 并且错误消失了:

    if (this as Base === bar) { }
    if (this === bar as Base) { }
    

    最简单的方法是使用 type assertion 扩大,但由于类型断言也可能不安全地缩小,您可能更愿意避免或补充一些更安全的东西:

    const thisBase: Base = this; if (thisBase === bar) { }
    if (this satisfies Base as Base === bar) { }
    

    无论如何,你都必须跳过一个小圈子,让TypeScript相信你是故意这样做的。这不是最优的,但每次“哦,拜托,这显然是故意的”,结果都有不少“哦,这实际上是个错误”。这类事情本质上总是具有启发性的,由于开发人员的意图不能被完美地捕捉到,他们能做的最好的事情就是尝试找到权衡最大化的地方 平均的 开发者体验。

    Playground link to code