eslint-plugin-rxjs-angular icon indicating copy to clipboard operation
eslint-plugin-rxjs-angular copied to clipboard

`ngOnDestroy` is not implemented raised by prefer-takeuntil rule when ngOnDestroy is in a super class

Open ldulary opened this issue 5 years ago • 7 comments

Considering this super class :

import { Directive, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';

@Directive()
export class Destroy implements OnDestroy {
    protected destroyed$ = new Subject();

    public ngOnDestroy() {
        this.destroyed$.next();
        this.destroyed$.unsubscribe();
    }
}

In the components extending Destroy, having takeUntil(this.destroyed$) before each subscribe should be enough to fullfill prefer-takeuntil rule. But there is the following issue : error `ngOnDestroy` is not implemented rxjs-angular/prefer-takeuntil

ldulary avatar Jun 24 '20 15:06 ldulary

See this comment on the TSLint rule equivalent:

I imagine this would be possible, but complicated and I can't see myself having the time to do this anytime soon.

cartant avatar Jun 24 '20 22:06 cartant

Thanks for your answer. Meanwhile I will just set checkDestroy to false.

ldulary avatar Jun 25 '20 07:06 ldulary

It's safer use

// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class MyComponent ...

or

  // eslint-disable-next-line rxjs-angular/prefer-takeuntil
  public ngOnDestroy() {
    super.ngOnDestroy();
  }

silveoj avatar Feb 09 '21 00:02 silveoj

See this comment on the TSLint rule equivalent:

I imagine this would be possible, but complicated and I can't see myself having the time to do this anytime soon.

For both prefer-composition and prefer-takeuntil, May I suggest configuration to ignore if extended from a certain class? (and ngOnDestroy is not reimplemented in the child class). In my case I'd configure it for "BaseComponent". The rules would still naturally enforce ngOnDestroy and takeUntil for the BaseComponent anyway (since it doesn't extend itself).

@Component({
  selector: 'app-footer',
  templateUrl: './footer.component.html',
  styleUrls: ['./footer.component.less'],
})
export class FooterComponent extends BaseComponent implements OnInit {
  // Some code
}

Or even simpler as an easy / naive way to add support: let us disable the ngOnDestroy is not implemented message, while keeping the Forbids calling subscribe without an accompanying takeUntil one.

SamuelT-Beslogic avatar Jan 18 '22 21:01 SamuelT-Beslogic

@Samuel-Beslogic I just don't have the time to mess with these rules and I've not used them myself lately - as I've not used Angular for years. Rather than messing with them to work with base-class/component shenanigans, maybe the plain vanilla RxJS rules would be a better fit:

  • https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-ignored-subscription.md
  • https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-unsafe-takeuntil.md

cartant avatar Jan 26 '22 07:01 cartant

@cartant Part of your rule does something important that neither of those two do: it ensures takeuntil used on subscriptions should properly unsubscribe when the component is destroyed.

It's just that there's part of the rule that wrongly assumes all components need to implement OnDestroy by themselves.

Even just splitting the takeUntil rule in two (or being able to disable the check for implementing OnDestroy) would be sufficient. Forgetting takeUntil happens often. But when typing takeUntil(this.unsubscribe) it's not hard to see that I just need to extend our BaseComponent if Typescript tells me that this.unsubscribe does not exist.

I'm willing to spend some time on this and create a PR if I have a working solution. The AST Selector for the extend class would look something like this ClassDeclaration[superClass.name='${baseComponent}']

Avasam avatar Mar 11 '22 03:03 Avasam

@ldulary #10 You can install github:Avasam/eslint-plugin-rxjs-angular#dist in the mean time with the following configuration:

"rxjs-angular/prefer-composition": [
  "error",
  {
    "superClass": [
      "BaseComponent"
    ]
  }
],
"rxjs-angular/prefer-takeuntil": [
  "error",
  {
    "superClass": [
      "BaseComponent"
    ]
  }
],

Avasam avatar May 21 '22 22:05 Avasam