Typescript 4:临时覆盖原型方法

Typescript 4: Temporary overriding of a prototype method

下一个代码在 typescript 3.3.3 上运行(在 repl.it 上)。它会在每次其他调用时覆盖或恢复为原型的方法。

class Foo {
  foo () {
    this.foo = function() {
      console.log('instance call')
      delete this.foo // ⟵ Compilation problem with TS4 here
    }
    console.log('prototype call')
  }
}
const f = new Foo()
f.foo()
f.foo()
f.foo()
f.foo()

输出为:

prototype call
instance call
prototype call
instance call

但是此代码无法在 typescript 4 上编译。删除行发出“'delete' 运算符的操作数必须是可选的。”错误。

有什么方法可以解决这个特定的编译问题吗? 可能会有细微的变化,因为我经常使用这种范式。

TypeScript 4.0 添加了 you may only delete properties that are optional 的限制。由于 foo 属性 或 Foo 是必需的,因此您不能 delete 它。从原型中也存在的实例中删除某些东西的用例可能没有被考虑,或者认为不够重要。


通常解决此问题的一种方法是使 foo 方法可选,如下所示:

class Foo {
  foo?() {
    this.foo = function () {
      console.log('instance call')
      delete this.foo
    }
    console.log('prototype call')
  }
}
const f = new Foo()
if (f.foo) f.foo()
if (f.foo) f.foo()
if (f.foo) f.foo()
if (f.foo) f.foo()

但这可能不是您想做的,因为您知道foo将始终存在于继承链的某处。


相反,您可以在 delete 语句中使用 type assertion 来告诉编译器将 this 视为其 foo 属性 是可选的:

class Foo {
  foo() {
    this.foo = function () {
      console.log('instance call')
      delete (this as Partial<Foo>).foo  
    }
    console.log('prototype call')
  }
}
const f = new Foo()
f.foo()
f.foo()
f.foo()
f.foo()

Playground link to code