Skip to content

Commit ee51091

Browse files
ZamiellJoshuaKGoldberg
authored andcommitted
feat(eslint-plugin): [switch-exhaustiveness-check] add an option to warn against a default case on an already exhaustive switch (typescript-eslint#7539)
* feat: switch-exhaustiveness-check checks for dangerous default case * fix: spelling * fix: comment * fix: docs * feat: allowDefaultCase option * fix: tests * fix: lint * fix: prettier * refactor: finish merge * fix: format * fix: lint * chore: update docs * chore: update docs * chore: format * fix: test * fix: tests * fix: tests * fix: tests * fix: test * fix: test * fix: tests * Update packages/eslint-plugin/src/rules/switch-exhaustiveness-check.ts Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com> * fix: double options in docs * Update packages/eslint-plugin/docs/rules/switch-exhaustiveness-check.md Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com> * feat: simplify code flow * Update packages/eslint-plugin/src/rules/switch-exhaustiveness-check.ts Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com> * fix: grammar * Update packages/eslint-plugin/src/rules/switch-exhaustiveness-check.ts Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com> * fix: wording on option * Update packages/eslint-plugin/docs/rules/switch-exhaustiveness-check.md Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com> * docs: add playground link * Update packages/eslint-plugin/src/rules/switch-exhaustiveness-check.ts Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com> * chore: add punctuation * Update packages/eslint-plugin/src/rules/switch-exhaustiveness-check.ts Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com> * chore: remove comment * refactor: rename option * fix: prettier * fix: lint * fix: tests * refactor: better metadata * fix: tests * refactor: rename interface * refactor: make interface readonly --------- Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com>
1 parent e70c19a commit ee51091

File tree

4 files changed

+259
-100
lines changed

4 files changed

+259
-100
lines changed

packages/eslint-plugin/docs/rules/switch-exhaustiveness-check.md

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,51 @@ description: 'Require switch-case statements to be exhaustive.'
66
>
77
> See **https://typescript-eslint.io/rules/switch-exhaustiveness-check** for documentation.
88
9-
When working with union types or enums in TypeScript, it's common to want to write a `switch` statement intended to contain a `case` for each constituent (possible type in the union or the enum).
9+
When working with union types or enums in TypeScript, it's common to want to write a `switch` statement intended to contain a `case` for each possible type in the union or the enum.
1010
However, if the union type or the enum changes, it's easy to forget to modify the cases to account for any new types.
1111

1212
This rule reports when a `switch` statement over a value typed as a union of literals or as an enum is missing a case for any of those literal types and does not have a `default` clause.
1313

14-
There is also an option to check the exhaustiveness of switches on non-union types by requiring a default clause.
14+
## Options
15+
16+
### `"allowDefaultCaseForExhaustiveSwitch"`
17+
18+
Defaults to true. If set to false, this rule will also report when a `switch` statement has a case for everything in a union and _also_ contains a `default` case. Thus, by setting this option to false, the rule becomes stricter.
19+
20+
When a `switch` statement over a union type is exhaustive, a final `default` case would be a form of dead code.
21+
Additionally, if a new value is added to the union type, a `default` would prevent the `switch-exhaustiveness-check` rule from reporting on the new case not being handled in the `switch` statement.
22+
23+
#### `"allowDefaultCaseForExhaustiveSwitch"` Caveats
24+
25+
It can sometimes be useful to include a redundant `default` case on an exhaustive `switch` statement if it's possible for values to have types not represented by the union type.
26+
For example, in applications that can have version mismatches between clients and servers, it's possible for a server running a newer software version to send a value not recognized by the client's older typings.
27+
28+
If your project has a small number of intentionally redundant `default` cases, you might want to use an [inline ESLint disable comment](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1) for each of them.
29+
30+
If your project has many intentionally redundant `default` cases, you may want to disable `allowDefaultCaseForExhaustiveSwitch` and use the [`default-case` core ESLint rule](https://eslint.org/docs/latest/rules/default-case) along with [a `satisfies never` check](https://www.typescriptlang.org/play?#code/C4TwDgpgBAYgTgVwJbCgXigcgIZjAGwkygB8sAjbAO2u0wG4AoRgMwSoGNgkB7KqBAGcI8ZMAAULRCgBcsacACUcwcDhIqAcygBvRlCiCA7ig4ALKJIWLd+g1A7ZhWXASJy99+3AjAEcfhw8QgApZA4iJi8AX2YvR2dMShoaTA87Lx8-AIpaGjCkCIYMqFiSgBMIFmwEfGB0rwMpMUNsbkEWJAhBKCoIADcIOCjGrP9A9gBrKh4jKgKikYNY5cZYoA).
31+
32+
### `requireDefaultForNonUnion`
33+
34+
Defaults to false. It set to true, this rule will also report when a `switch` statement switches over a non-union type (like a `number` or `string`, for example) and that `switch` statement does not have a `default` case. Thus, by setting this option to true, the rule becomes stricter.
35+
36+
This is generally desirable so that `number` and `string` switches will be subject to the same exhaustive checks that your other switches are.
37+
38+
Examples of additional **incorrect** code for this rule with `{ requireDefaultForNonUnion: true }`:
39+
40+
```ts option='{ "requireDefaultForNonUnion": true }' showPlaygroundButton
41+
const value: number = Math.floor(Math.random() * 3);
42+
43+
switch (value) {
44+
case 0:
45+
return 0;
46+
case 1:
47+
return 1;
48+
}
49+
```
50+
51+
Since `value` is a non-union type it requires the switch case to have a default clause only with `requireDefaultForNonUnion` enabled.
52+
53+
<!--/tabs-->
1554

1655
## Examples
1756

@@ -181,27 +220,6 @@ switch (fruit) {
181220

182221
<!--/tabs-->
183222

184-
## Options
185-
186-
### `requireDefaultForNonUnion`
187-
188-
Examples of additional **incorrect** code for this rule with `{ requireDefaultForNonUnion: true }`:
189-
190-
```ts option='{ "requireDefaultForNonUnion": true }' showPlaygroundButton
191-
const value: number = Math.floor(Math.random() * 3);
192-
193-
switch (value) {
194-
case 0:
195-
return 0;
196-
case 1:
197-
return 1;
198-
}
199-
```
200-
201-
Since `value` is a non-union type it requires the switch case to have a default clause only with `requireDefaultForNonUnion` enabled.
202-
203-
<!--/tabs-->
204-
205223
## When Not To Use It
206224

207225
If you don't frequently `switch` over union types or enums with many parts, or intentionally wish to leave out some parts, this rule may not be for you.

0 commit comments

Comments
 (0)