prefer_switch_with_enums
This rule flags an if-else chain of three or more branches that compares the same enum value against different constants.
Why use this rule
Section titled “Why use this rule”A switch over an enum is checked for exhaustiveness. Add a constant to the enum and the compiler points at every switch that must now handle it, turning the change into a guided refactor.
An if-else chain gets no such check. A new constant falls through to the final else, or past the chain entirely, and the bug shows up at runtime in whichever branch forgot about it. The chain is also longer to read: the reader has to confirm each branch tests the same subject.
The same blind spot applies to a condition that ||-chains comparisons, and to a membership test over a literal set of constants: in both cases adding an enum constant changes nothing and the compiler stays silent.
See also: Dart: exhaustiveness checking
String describe(Status status) { if (status == Status.active) { return 'Active'; } else if (status == Status.inactive) { return 'Inactive'; } else if (status == Status.pending) { return 'Pending'; } return '';}
// Comparisons combined with ||if (status == Status.active || status == Status.inactive || status == Status.pending) { handle();}
// Membership test over a literal set of constantsif ({Status.active, Status.inactive, Status.pending}.contains(status)) { handle();}String describe(Status status) => switch (status) { Status.active => 'Active', Status.inactive => 'Inactive', Status.pending => 'Pending',};
final handled = switch (status) { Status.active || Status.inactive || Status.pending => true,};Known limitations
Section titled “Known limitations”The rule requires the whole condition to be replaceable, so it stays silent when:
- Fewer than three enum comparisons are involved — a short chain is not worth restructuring. Comparisons joined by
||count individually, soa == E.x || a == E.yin one branch plusa == E.zin the next reaches the threshold. - The branches test different subjects, or mix an enum comparison with an unrelated condition.
- The enum is nullable, since a
nullcase needs handling a plain switch over constants does not give.
For contains, only a literal receiver is reported. A named collection (const known = {...}; known.contains(v)) is a deliberate, reusable set rather than an inlined branch, so it is left alone.
Operand order does not matter: Status.active == status is recognised the same as status == Status.active.
Turning this rule off
Section titled “Turning this rule off”This rule is in the opinionated preset, so it is on with
preset: opinionated, or by name:
rules: prefer_switch_with_enums: trueTo turn it off again:
rules: prefer_switch_with_enums: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Options
Section titled “Options”many_lints: rules: prefer_switch_with_enums: ignore_contains: truerules: prefer_switch_with_enums: ignore_contains: true| Option | Type | Default | Description |
|---|---|---|---|
ignore_contains |
bool | false |
Skip {E.a, E.b}.contains(value) membership tests, reporting only if-else and ` |
Related rules
Section titled “Related rules”avoid_wildcard_cases_with_enums— Keep exhaustiveness checking by listing enum cases explicitly.prefer_wildcard_pattern— Use the wildcard pattern ‘_’ instead of ‘Object()’ for catch-all cases.prefer_switch_expression— Suggest converting switch statements to switch expressions.avoid_nested_conditional_expressions— Flag a conditional nested inside another.