Skip to content

Enhancement: [switch-exhaustiveness-check] considerDefaultExhaustiveForUnions only with comment #10251

Closed as not planned
@FloEdelmann

Description

@FloEdelmann

Before You File a Proposal Please Confirm You Have Done The Following...

My proposal is suitable for this project

  • I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).

Link to the rule's documentation

https://typescript-eslint.io/rules/switch-exhaustiveness-check/

Description

I like the new default behavior (considerDefaultExhaustiveForUnions: false), so that I have to explicitly list every union case in a switch statement. However, sometimes there are really big unions where I'd like to rely on the default case implicitly covering all other cases.

I don't want to disable the switch-exhaustiveness-check rule with an ESLint comment, because it will likely be missed and kept when changing the default case, given that it has to be above the switch (…) { line and not above the default: line and is thus out of sight.

Example
declare const letter: 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';

// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- default case handles letters Q to Z
switch (letter) {
  case 'A': {
    console.log('A');
    break;
  }
  case 'B': {
    console.log('B');
    break;
  }
  case 'C': {
    console.log('C');
    break;
  }
  case 'D': {
    console.log('D');
    break;
  }
  case 'E': {
    console.log('E');
    break;
  }
  case 'F': {
    console.log('F');
    break;
  }
  case 'G': {
    console.log('G');
    break;
  }
  case 'H': {
    console.log('H');
    break;
  }
  case 'I': {
    console.log('I');
    break;
  }
  case 'J': {
    console.log('J');
    break;
  }
  case 'K': {
    console.log('K');
    break;
  }
  case 'L': {
    console.log('L');
    break;
  }
  case 'M': {
    console.log('M');
    break;
  }
  case 'N': {
    console.log('N');
    break;
  }
  case 'O': {
    console.log('O');
    break;
  }
  case 'P': {
    console.log('P');
    break;
  }
  default: {
    console.log('Other');
  }
}

Instead, I propose adding a new option value for considerDefaultExhaustiveForUnions (and maybe even making it the default instead of false): 'onlyWithComment'
With this option, a default case on its own would still not be considered exhaustive, but adding a comment right before the default case would silence the rule.

Example
declare const letter: 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';

switch (letter) {
  case 'A': {
    console.log('A');
    break;
  }
  case 'B': {
    console.log('B');
    break;
  }
  case 'C': {
    console.log('C');
    break;
  }
  case 'D': {
    console.log('D');
    break;
  }
  case 'E': {
    console.log('E');
    break;
  }
  case 'F': {
    console.log('F');
    break;
  }
  case 'G': {
    console.log('G');
    break;
  }
  case 'H': {
    console.log('H');
    break;
  }
  case 'I': {
    console.log('I');
    break;
  }
  case 'J': {
    console.log('J');
    break;
  }
  case 'K': {
    console.log('K');
    break;
  }
  case 'L': {
    console.log('L');
    break;
  }
  case 'M': {
    console.log('M');
    break;
  }
  case 'N': {
    console.log('N');
    break;
  }
  case 'O': {
    console.log('O');
    break;
  }
  case 'P': {
    console.log('P');
    break;
  }
  // default handles letters Q to Z
  default: {
    console.log('Other');
  }
}

Fail

declare const literal: 'a' | 'b';

switch (literal) {
  case 'a':
    break;
  default:
    break;
}

Pass

declare const literal: 'a' | 'b';

switch (literal) {
  case 'a':
    break;
  // all other cases
  default:
    break;
}

Additional Info

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancement: plugin rule optionNew rule option for an existing eslint-plugin ruleevaluating community engagementwe're looking for community engagement on this issue to show that this problem is widely importantlocked due to agePlease open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing.package: eslint-pluginIssues related to @typescript-eslint/eslint-plugin

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions