avoid_nested_conditional_expressions
Flags a conditional expression (? :) nested inside another one. a ? b : (c ? d : e) packs a decision tree onto one line and the reader has to track which ? each : belongs to.
This rule is in the opinionated preset.
With max_depth: 1, the default, one nesting level is already over the limit:
String label(int score) => score > 100 ? 'high' : (score > 50 ? 'medium' : 'low');A switch expression lines the branches up:
String label(int score) => switch (score) { > 100 => 'high', > 50 => 'medium', _ => 'low',};When the branches are not about one value
Section titled “When the branches are not about one value”A switch needs a single subject. When the tests are unrelated, early returns are the way out:
// Don'tString shippingLabel(bool express, bool international, double weightKg) => express ? (international ? 'Express international' : 'Express domestic') : 'Standard';// DoString shippingLabel(bool express, bool international, double weightKg) { if (!express) return 'Standard'; if (international) return 'Express international'; return 'Express domestic';}Nesting in the then-branch counts the same
Section titled “Nesting in the then-branch counts the same”Depth is measured down both branches and the deeper one wins, so a conditional in the then position is reported just as readily as one in the else:
// Don'tString tier(bool member, int years) => member ? (years > 5 ? 'gold' : 'silver') : 'guest';Allowing exactly one level
Section titled “Allowing exactly one level”Some codebases accept a single nesting and want only the deeper ones flagged. With max_depth: 2, the two-level example above passes and a third level reports:
many_lints: rules: avoid_nested_conditional_expressions: enabled: true max_depth: 2rules: avoid_nested_conditional_expressions: enabled: true max_depth: 2// Accepted at max_depth: 2String tier(bool member, int years) => member ? (years > 5 ? 'gold' : 'silver') : 'guest';
// Still reported — three levelsString band(int n) => n > 100 ? 'a' : (n > 50 ? 'b' : (n > 10 ? 'c' : 'd'));Known limitations
Section titled “Known limitations”The diagnostic lands on the outermost conditional of a chain, so one nested tree gives one report rather than one per level. The message names the measured depth and the configured limit.
Nesting is only followed through the ? and : branches, not through everything written inside them. A conditional passed as an argument — outer ? f(a ? b : c) : d — starts its own count, so each is measured separately and neither may reach the limit.
The condition itself is not counted. (a ? b : c) ? d : e is depth 1.
There is no quick fix: whether the right replacement is a switch, early returns, or a named helper depends on what the branches mean.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
max_depth |
int | 1 |
Maximum allowed conditional-expression nesting depth |
Turning this rule off
Section titled “Turning this rule off”To disable this rule:
rules: avoid_nested_conditional_expressions: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”prefer_conditional_expressions— Collapse a two-way if/else into a conditional expression.prefer_switch_expression— Suggest converting switch statements to switch expressions.prefer_switch_with_enums— Use a switch instead of an if-else chain over enum constants.avoid_contradictory_expressions— Detect logical AND conditions that always evaluate to false.