Как принудительно вызвать `супер.ngOnDestroy`

#angular #typescript #observable #abstract-class #jasmin

Вопрос:

У меня есть абстрактный класс, который помогает избежать повторяющегося кода (для отмены подписки на наблюдаемые объекты), он выглядит так:

 export abstract class SubscriptionManagmentDirective implements OnDestroy {
  componetDestroyed = new Subject<void>()

  constructor() {}

  ngOnDestroy(): void {
    this.componetDestroyed.next()
    this.componetDestroyed.unsubscribe()
  }
}
 

В некоторых случаях случалось, что я переопределял ngOnDestroy и забывал звонить super.ngOnDestroy() , а затем подписки сходили с ума.
Я добавил модульный тест к расширяющимся компонентам, чтобы проверить, что были вызваны подписки без подписки, но для этого мне нужно не забыть их добавить.

Мой вопрос таков,

  • есть ли способ принудительного вызова, который super.ngOnDestroy() вызывается всякий раз, когда компонент расширяется?
  • или есть способ написать модульный тест для абстрактного класса, который будет проверяться на любом компоненте, расширяющем этот класс?

Любая помощь будет признательна, спасибо.

Ответ №1:

Я думаю, что лучшим подходом к этому было бы добавление "noImplicitOverride": true в ваш tsconfig. Это не обязательно поможет вам запомнить вызов супер-метода, но это заставит вас четко указывать методы переопределения, что приведет к ошибке компиляции в тех случаях, когда вы переопределяете метод без использования override ключевого слова. Затем разработчик должен решить, нужно ли вызывать суперметод или нет.

https://www.typescriptlang.org/tsconfig#noImplicitOverride

Ответ №2:

  1. Нет, такого способа автоматического вызова метода из абстрактного не существует.
  2. Вы должны проводить модульный тест только в изоляции. Просто создайте встроенный тестовый класс, который расширяет ваш абстрактный, а затем модульный тест ngOnDestroy . Этого вполне достаточно.

Ответ №3:

Я могу придумать только один способ, очень банальный и уродливый. Одна вещь, которая принудительно выполняется super() , — это вызов в конструкторе самим машинописным текстом. Поэтому вы могли бы

 class Foo {
  constructor() {
    const oldNgOnDestroy = this.ngOnDestroy;

    this.ngOnDestroy = function() {
      console.log("decorated ngOnDestroy");
      return oldNgOnDestroy();
    }.bind(this);
  }

  ngOnDestroy() {
    console.log("original ngOnDestroy");
  }
}

class Bar extends Foo {
  constructor() {
    super();
  }
}

class Baz extends Foo {
  constructor() {
    super();
  }

  ngOnDestroy() {
    console.log("custom ngOnDestroy");
  }
}

const bar = new Bar();
bar.ngOnDestroy();
const baz = new Baz();
baz.ngOnDestroy(); 

Как я уже сказал, халтурно и некрасиво.