Else-If Chain Missing Final Else

ID

javascript.else_if_without_else

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Code Smell

Language

JavaScript

Tags

code-style, conditional, control-flow

Description

Disabled by default. No syntactic signal separates an intended decision table from a guard chain, so a review of real projects found almost no actionable report: dispatch chains where no match is a deliberate no-op, and chains whose trailing return/throw already acts as the final else, are indistinguishable from a genuine omission.

Reports an if / else if chain that does not end with a plain else. Only chains containing at least one else if are reported, and each chain is reported once, at its outermost if. A lone if, and a plain if / else, are not reported.

Any final else closes the chain, an empty one included: an empty if / else block is reported by javascript.no_empty, and one construct answering to two rules is duplicate reporting.

Rationale

Repeating a condition turns the chain into a decision table, and the reader takes the missing final else to mean the listed conditions cover every input. When they do not, control simply leaves the chain with whatever state it already had — the branch nobody wrote a test for. A final else costs one line and either handles the remaining case or documents, by throwing or logging, the author’s belief that there is none.

function fee(tier) {
  let amount = 0;

  if (tier === "gold") {         // FLAW — an unknown tier silently pays nothing
    amount = 1;
  } else if (tier === "silver") {
    amount = 2;
  }

  return amount;
}

Remediation

Close the chain with an else. Handle the remaining case if there is one; otherwise throw, log the unexpected value, or return a well-defined default, so that an input outside the enumerated conditions is impossible to miss.

function fee(tier) {
  if (tier === "gold") {         // OK — the remaining case is stated
    return 1;
  } else if (tier === "silver") {
    return 2;
  } else {
    throw new RangeError(`unknown tier: ${tier}`);
  }
}

© 2026 Xygeni. All rights reserved