TypeScript Flag 'instanceof' expressions that are provably always true or false

lnlaulya  于 4个月前  发布在  TypeScript
关注(0)|答案(6)|浏览(54)

建议

在重构代码时,TypeScript通常能够很好地发现并报告由于类型更改而导致现有代码出错的情况。这使得我们可以“充满信心地重构”。考虑到TypeScript的主要目标之一是“静态识别可能出错的构造”,这一点并不令人惊讶。
有一个常见的情况,TypeScript在类型重构时“盲目”且不会报告错误。这种情况涉及到使用'instanceof'运算符。该运算符可以在没有意义的情况下使用——例如,左侧指定的类型与右侧指定的类型之间没有任何可能的关系。
为了帮助开发者避免这种常见的编程错误,我建议TypeScript对于任何在编译时可以确信始终为真或假的'instanceof'表达式报告错误。这样的表达式很可能是程序员无意中编写的,应该被标记为错误。最好的情况是,这样的操作代表了不必要的代码,给运行时带来开销。

示例

// ClassB is a subclass of ClassA.
class ClassA {}
class ClassB extends ClassA {}

// ClassC has nothing to do with either
// ClassA or ClassB.
class ClassC {
    method1() {}
}

function function1(param1: ClassB) {
    // Static analysis can prove this expression
    // will always evaluate to false. It's a common
    // source of programming errors, especially during
    // refactoring.
    if (param1 instanceof ClassC) {
        // This call isn't even valid given that param1
        // was declared as type ClassB.
        param1.method1();
    }

    // Static analysis can prove this expression will
    // always evaluate to true, so at best it's unnecessary
    // runtime overhead and more commonly is a behavior
    // that is unintended by the programmer.
    if (param1 instanceof ClassA) {
        // ...
    }
}

是否存在任何合法的使用场景,其中结果在所有情况下都可以静态地证明为真或假?我想不出任何例子,但可能是我忽略了一些特殊的用例。如果有的话,可以将此检查作为可选的编译器开关添加,以保留当前的行为。

qybjjes1

qybjjes11#

顺便说一下,我刚刚在pyright中添加了一个类似的功能(一个"reportUnnecessaryIsInstance"开关)。Pyright是一个从TypeScript类型检查器借用了许多概念的Python类型检查器。Python的"isinstance"调用类似于Javascript的"instanceof"运算符。当我向pyright添加这个新功能时,它立即揭示了我团队的Python代码库中的大约十二个错误。

uidvcgyl

uidvcgyl2#

我最近修复了一些本来可以防止的bug,如果TypeScript将这个错误视为编译错误的话。在某人进行重构后,他们在函数的后面错过了一个instanceof检查,现在这个函数总是返回false。
我认为这与以下错误类似:

function foo(value: string) {
    return value === 'hello' && value === 'goodbye';
}

编译器给你这个错误:This condition will always return 'false' since the types '"hello"' and '"goodbye"' have no overlap. (2367)

gv8xihay

gv8xihay3#

+1.刚被咬了一口,我以为TS会检查这个并阻止我做这样愚蠢的事情。我试图做

if (treeNode instanceof TreeValue) { ... } // TreeValue = typeof treeNode.value

在这种情况下,对于TS来说,标记为始终为假应该是轻而易举的。

4si2a6ki

4si2a6ki4#

+1,刚刚也被这个问题烧到了。

mqkwyuun

mqkwyuun5#

我也很想拥有这个功能,但我想知道它是否可能有其他意想不到的后果。instanceof 以一种“名义类型”的方式检查一个对象是否是某个类的示例,但Typescript的所有检查都是基于结构类型的。这意味着,就Typescript而言,一个声称是某个class的变量,实际上可能并不是那个类的示例,只是具有兼容的结构。
以下示例虽然有些牵强,但仍然可以进行类型检查。它表明在运行时,sayHello函数中的参数person: Person不一定是Person类的示例:

class Person{
  constructor(public readonly name: string){}
}

function sayHello(person: Person){
  if(person instanceof Person){
    console.log(`hello, ${person.name}`)
  }
}

sayHello({name: "Bob"}) // this type-checks and does not print "hello"
p4tfgftt

p4tfgftt6#

距离上次由这个引起的bug已经过去了0天。

相关问题