Angular utility for ensuring exhaustive checks on TypeScript discriminated unions, enhancing type safety and reliability.
$ npm install ngx-exhaustive-check
Without an exhaustive check, the code may compile successfully, but this can lead to runtime errors:
import { Component } from '@angular/core';
enum Answer {
Yes,
No,
+ Maybe,
}
@Component({
selector: 'app-root',
standalone: true,
template: `
@switch (answer) {
@case (Answer.Yes) {}
@case (Answer.No) {}
@default {}
}
`,
})
export class AppComponent {
answer: Answer = Answer.Yes;
Answer = Answer;
}
With an exhaustive check, the compilation will fail, making your code more reliable:
import { Component } from '@angular/core';
+ import { ExhaustiveCheckPipe } from 'ngx-exhaustive-check';
enum Answer {
Yes,
No,
+ Maybe,
}
@Component({
selector: 'app-root',
standalone: true,
+ imports: [ExhaustiveCheckPipe],
template: `
@switch (answer) {
@case (Answer.Yes) {}
@case (Answer.No) {}
@default {
+ {{ answer | exhaustiveCheck }}
<!-- ^^^^^^ Argument of type 'Answer' is not assignable to parameter of type 'never'. -->
}
}
`,
})
export class AppComponent {
answer: Answer = Answer.Yes;
Answer = Answer;
}
Sometimes, if you just want to ignore some cases, you can do this:
enum Answer {
Yes,
No,
+ NoOp1,
+ NoOp2,
}
@switch (answer) {
@case (Answer.Yes) {}
@case (Answer.No) {}
+ @case (Answer.NoOp1) {}
+ @case (Answer.NoOp2) {}
@default {
{{ answer | exhaustiveCheck }}
}
}
With ngx-exhaustive-check, you can achieve this by passing the satisfies
parameter as well:
@switch (answer) {
@case (Answer.Yes) {}
@case (Answer.No) {}
@default {
- {{ answer | exhaustiveCheck }}
+ {{ answer | exhaustiveCheck: [Answer.NoOp1, Answer.NoOp2] }}
}
}
This is useful when you want to apply the same action to these cases.