what to avoid
strict settings of angular and compiler
ng new MyAwesomeAngularApp
regular TS settings
regular linter settings
default Angular Compiler settings
any is allowed!
ng new MyAwesomeAngularApp --strict
{
"compilerOptions": {
...
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
},
"angularCompilerOptions": {
"strictInjectionParameters": true,
"strictTemplates": true
}
}
"schematics": {
"@schematics/angular:application": {
"strict": true
}
},
...
"angularCompilerOptions": {
"strictInjectionParameters": true,
"strictTemplates": true
}
"fullTemplateTypeCheck": true,
"trace": true,
"preserveWhitespaces": true
"no-any": true
"promise-function-async": true
"await-promise": true
"no-async-without-await": true
"no-debugger": true
"no-duplicate-variable": true
"no-var-keyword": true
"max-file-line-count": 140
"no-duplicate-imports": true
...
ANY shall not pass
public ngOnInit(): void {
const movie = {
name: 'Game of Thrones',
};
this.showToast(movie);
}
private showToast(item: any): void {
this.toaster.show(`Today's movie is: ${item.name}`);
}
public ngOnInit(): void {
const movie = {
title: 'Game of Thrones',
};
this.showToast(movie);
}
private showToast(item: any): void {
this.toaster.show(`Today's movie is: ${item.name}`);
}
interface Movie {
name: string;
}
public ngOnInit(): void {
const movie: Movie = {
name: 'Game of Thrones',
};
this.showToast(movie);
}
private showToast(item: Movie): void {
this.toaster.show(`Today's movie is: ${item.name}`);
}
interface Movie {
title: string;
}
public ngOnInit(): void {
const movie: Movie = {
name: 'Game of Thrones',
};
this.showToast(movie);
}
private showToast(item: Movie): void {
this.toaster.show(`Today's movie is: ${item.name}`);
}
export class CustomLineGeometry extends LineGeometry {
constructor(geometry?: BufferGeometry) {
super();
(this as any)._maxInstanceCount = 100;
}
}
ngOnInit() {
console.log('Initialized');
this.timerService.initTimer()
.subscribe(x => {
this.result = x;
console.log(x);
});
}
ngOnDestroy() {
console.log('Destroyed');
}
subscription: Subscription;
ngOnInit() {
console.log('Initialized');
this.subscription = this.timerService.initTimer()
.subscribe(x => {
this.result = x;
console.log(x);
});
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
console.log('Destroyed');
}
alive = true;
ngOnInit() {
console.log('Initialized');
this.timerService.initTimer()
.pipe(takeWhile(() => {
console.log('check'); return this.alive; }))
.subscribe(x => {
this.result = x;
console.log(x);
});
}
ngOnDestroy() {
this.alive = false;
console.log('Destroyed');
}
unsubscribe: Subject<void> = new Subject();
ngOnInit() {
console.log('Initialized');
this.timerService.initTimer()
.pipe(takeUntil(this.unsubscribe))
.subscribe(x => {
this.result = x;
console.log(x);
});
}
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
console.log('Destroyed');
}
import {untilDestroyed} from "ngx-take-until-destroy";
ngOnInit() {
console.log('Initialized');
this.timerService.initTimer()
.pipe(untilDestroyed(this))
.subscribe(x => {
this.result = x;
console.log(x);
});
}
ngOnDestroy() {
console.log('Destroyed');
}
@Component({
template: `
<span>
{{ this.service.getData() | async }}
</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SubscriptionComponent {
constructor(private service: Service) {}
}
@Component({
template: `<span>{{ this.result$ | async }}</span>`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SubscriptionComponent
implements OnInit, OnDestroy {
result$: Observable<number>;
ngOnInit() {
console.log('Initialized');
this.result$ = this.timerService.initTimer()
.pipe(tap(x => { console.log(x); }));
}
ngOnDestroy() {
console.log('Destroyed');
}
}
<ng-container *ngIf="{
id: id$ | async,
count: count$ | async
} as data">
Id: {{ data.id }}
Count: {{ data.count }}
</ng-container>
id$: Observable<number>;
count$: Observable<number>;
<div>
Id: {{ id$ | async }}
Count: {{ count$ | async }}
</div>
id$: Observable<number>;
count$: Observable<number>;
ngOnInit() {
console.log('Initialized');
this.result$ = this.timerService
.initTimerForObject()
.pipe(tap(x => {
console.log(`Timer: ${x}`);
}));
this.id$ = this.result$.pipe(map(x => x.id));
this.count$ = this.result$.pipe(map(x => x.count));
}
<div>
Subscription result:
{{ id$ | async }} | {{ count$ | async }}
</div>
id$: Observable<number>;
count$: Observable<number>;
ngOnInit() {
this.result$ = this.timerService
.initTimerForObject()
.pipe(share());
this.id$ = this.result$.pipe(map(x => x.id));
this.count$ = this.result$.pipe(map(x => x.count));
}
observer1
observer2
Subject
Source
id$: Observable<number>;
count$: Observable<number>;
ngOnInit() {
this.result$ = this.timerService
.initTimerForObject()
.pipe(
share(),
);
this.id$ = this.result$.pipe(map(x => x.id));
this.count$ = this.result$.pipe(map(x => x.count));
}
<div>{{ id$ | async }} | {{ count$ | async }}</div>
<div>{{ id$ | async }} | {{ count$ | async }}</div>
id$: Observable<number>;
count$: Observable<number>;
ngOnInit() {
this.result$ = this.timerService
.initTimerForObject()
.pipe(
share(),
catchError((error: any) => {
console.log(error);
return of({ id: 0, count: 0 });
}),
);
this.id$ = this.result$.pipe(map(x => x.id));
this.count$ = this.result$.pipe(map(x => x.count));
}
rxjs-no-ignored-subscription
rxjs-no-ignored-subscribe
rxjs-no-ignored-observable
rxjs-no-ignored-error
rxjs-no-nested-subscribe
rxjs-no-unsafe-takeuntil
rxjs-prefer-async-pipe
https://www.nmpjs.com/package/rxjs-tslint-rules
<button type="button" (click)="sortCollection()">
Sort Collection</button>
<div *ngFor="let item of items; trackBy: trackByFn">
{{ getLabel(item) }}
</div>
getLabel(item: ItemData): string {
console.log(`Item ${item.id} label call`);
return `Item ${item.id}`;
}
@Pipe({ name: 'label'})
export class LabelPipe implements PipeTransform {
transform(value: Item, args?: any): string {
console.log(`Item ${value} label call`);
return `Item ${value.id}`;
}
}
<button type="button" (click)="sortCollection()">
Sort Collection</button>
<div *ngFor="let item of items; trackBy: trackByFn">
{{ item | label }}
</div>
items: ItemData[] = [{
parentId: 1,
name: 'Game Of Thrones',
},
{
parentId: 2,
name: 'The Lord of the Rings',
},
{
parentId: 3,
name: 'Big Bang Theory - Season 1',
},
{
parentId: 3,
name: 'Big Bang Theory - Season 2',
}];