Need help understanding switch case in JavaScript

I’m trying to use a switch case in JavaScript to handle several different conditions, but my code keeps falling through to the wrong case or hitting the default unexpectedly. I’m not sure if I’m structuring the cases or breaks properly, or if switch is even the right choice for this scenario. Can someone explain how to correctly set up a switch case with multiple conditions and share best practices to avoid common mistakes?

Your issue almost always comes from three things:

  1. Missing break
  2. Wrong comparison value
  3. Type mismatch

Quick checklist.

  1. Basic structure

switch (value) {
case ‘a’:
console.log(‘A’);
break;
case ‘b’:
console.log(‘B’);
break;
default:
console.log(‘default’);
}

Without break, execution falls through to the next case.

  1. Example of bad fallthrough

switch (x) {
case 1:
console.log(‘one’);
case 2:
console.log(‘two’);
default:
console.log(‘default’);
}

If x is 1, this prints:
one
two
default

Add breaks:

switch (x) {
case 1:
console.log(‘one’);
break;
case 2:
console.log(‘two’);
break;
default:
console.log(‘default’);
}

  1. Type issues

switch uses strict equality (===).

switch (‘1’) {
case 1:
console.log(‘one’);
break;
default:
console.log(‘default’);
}

This hits default, because ‘1’ !== 1.

So either:

a) Normalize types:

const n = Number(x);
switch (n) {
case 1:

}

b) Compare strings:

switch (x) {
case ‘1’:

}

  1. Grouping cases

If you want the same logic for several values, do this on purpose:

switch (day) {
case ‘sat’:
case ‘sun’:
console.log(‘weekend’);
break;
default:
console.log(‘weekday’);
}

Here fallthrough is intentional.

  1. Common pattern that bites people

switch (true) {
case score >= 90:
grade = ‘A’;
break;
case score >= 80:
grade = ‘B’;
break;
default:
grade = ‘F’;
}

This works, but you must keep the order. The first true case wins.

If you paste your switch code, people can point at the exact bug, but check for:

• Every case ends with break or return
• Case values match the type and value of your switch expression
• No unintended fallthrough between cases

Couple more angles to check, on top of what @viajantedoceu already covered:

  1. Watch out for expressions in switch
    If you do stuff like:
switch (x > 10) {
  case true:
    // ...
  case false:
    // ...
}

this is fine, but mixing switch (x) with case x > 10: is not:

switch (x) {
  case x > 10:   // <- this compares x to (x > 10), so x === true/false
    ...
}

That will basically always hit default, which looks super confusing.

  1. Unintended string trimming / casing
    If your cases are strings coming from user input / DOM:
switch (status) {
  case 'READY':
  case 'ready':
    ...

' ready ' or 'Ready' will miss both and go to default. Normalize once:

switch (status.trim().toLowerCase()) {
  case 'ready':
    ...
    break;
}
  1. Functions inside cases returning early
    Sometimes it “falls through” only because you don’t see the real flow:
switch (type) {
  case 'a':
    doA();      // does this throw or return?
    break;
  case 'b':
    doB();
    break;
  default:
    handleDefault();
}

If doA() throws, it will look like it skipped to default in the console, but the switch actually never finished. Check for errors in those called functions.

  1. Safer pattern when cases are complex
    If you find yourself nesting a lot of logic inside each case, sometimes if/else is simply clearer:
if (x === 1) {
  ...
} else if (x === 2) {
  ...
} else {
  ...
}

switch is nice when you’re matching exact values that are all the same kind and you can quickly eyeball the breaks. If you’re mixing ranges, conditions and type coercion, it gets error-prone fast.

If you paste your actual switch body, people can usually point to the exact “oh, there it is” bug in one line. Right now my guess is: either a case value expression that doesn’t equal what you think, or a normalize/trim issue making you hit default unexpectedly.