确保派生组件中的super.onDestroy()

时间:2019-03-04 09:06:25

标签: angular typescript inheritance

我有一堆具有非常相似的生命周期逻辑的组件,因此我创建了实现OnDestroy

的基本组件。
abstract class BaseComponent implements OnDestroy {
   subscriptions = new Array<Subscription>();
   get model() { return … }

   ngOnDestroy() {
      for (let s of subscriptions) s.unsubscribe();
   }
}

但是,当开发人员在扩展了ComponentBase的具体组件中编写自定义onOnDestroy方法时,他无法知道需要调用super.ngOnDestroy();

是否有某种(打字稿)方式来确保警告?还是模式其他组件继承? 也许可以对扩展ngOnDestroy的所有组件进行BaseComponent测试的单元测试?

4 个答案:

答案 0 :(得分:1)

大多数OOP语言不提供您要寻找的功能。一旦方法被子类覆盖,就无法强制子方法调用父实现。在打字稿中有an open issue在讨论此功能。

另一种方法是将基类上ngOnDestroy的实现标记为 final ,并为基类提供一种连接方法,以允许它们委派拆卸逻辑。例如:

abstract class BaseComponent implements OnDestroy {
   readonly subscriptions = new Array<Subscription>();
   get model() { return … }

   ngOnDestroy() {
      for (let s of subscriptions) s.unsubscribe();
      this.destroyHook();
   }

   // depending on your needs, you might want to have a default NOOP implementation
   // and allow child classes to override it. That way you wont need to spread NOOP 
   // implementations all over your code
   abstract protected destroyHook(): void;
}


class ChildClass extends BaseComponent {
   protected destroyHook(){//NOOP}
}

ts doesnt support an equivalent of the final logic ATM

另一个有趣的事实是,您遇到的这个问题来自您计划如何管理组件实例上的订阅。确实有更好的方法来执行此操作,其中一种方法是从源可观察对象直到中获取元素,直到该组件被破坏。像这样:

readonly observable$: Observable<string> = ....;
ngOnInit(){
   observable$.pipe(takeUntil(/*this instance is destroyed*/)).subscribe(...)
}

可以使用this

之类的库轻松对其进行存档。

答案 1 :(得分:1)

最简单的解决方案是定义孩子也需要返回的返回类型ngOnDestroy

class REQUIRED_SUPER {} //important to not export it, only we should be able to create it.

class Base implements OnDestroy {
    ngOnDestroy(): REQUIRED_SUPER {
        return new REQUIRED_SUPER;
    }
}

因此,如果您的用户也没有返回它,则意味着他没有调用您的方法。

export class Child extends Base implements OnDestroy {
    ngOnDestroy(): REQUIRED_SUPER {
    }
}

这导致TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.

要解决此问题,您的用户需要这样做:

ngOnDestroy(): REQUIRED_SUPER {
    return super.ngOnDestroy();
}

ngOnDestroy(): REQUIRED_SUPER {
    const superCalled = super.ngOnDestroy();
    //to stuff
    return superCalled;
}

答案 2 :(得分:0)

您可以确保开发人员从不在组件中编写subscribe,这样可以避免退订。

这意味着您将通过rxjs运算符和异步管道充分使用反应式编程。

您还可以使用自定义类装饰器来测试所有类成员,并查看它们是否为订阅实例。

您最终可以使用自定义的rxjs运算符,一旦您的组件遭到破坏,该运算符便会取消订阅。

它们有几个可用的选项,但是我建议使用第一个,因为它可以使您的代码更整洁并阅读onPush更改检测策略。

答案 3 :(得分:0)

我知道它晚了..但是对于需要它的人来说。!!!

export abstract class BaseClass implements OnDestroy {

ngOnDestroy(): void { }

constructor() {
    const refOnDestroy = this.ngOnDestroy;
    this.ngOnDestroy = () => {
        refOnDestroy();
       // perform unsubscriptions here
       // eg: for (let s of subscriptions) s.unsubscribe();
    };
 }
}

Detailed description can be found here