I’m struggling to get a JavaScript switch statement to behave the way I expect. Some cases don’t seem to run, and the default block fires even when a matching value should exist. I’m not sure if I’m missing break statements, comparing the wrong types, or structuring my logic incorrectly. Can someone explain how switch statements really work in JavaScript and show a simple, correct example so I can compare it to my code?
Most switch bugs in JS come from a few common things. You can check these one by one.
-
Type mismatch
switch uses strict equality (===).
So this fails:
let x = ‘1’;
switch (x) {
case 1:
console.log(‘number 1’);
break;
default:
console.log(‘default’);
}
You get ‘default’.
Make sure the types match. Log typeof value before the switch:
console.log(value, typeof value); -
Missing break
If you forget break, execution falls through to the next case and even to default:
switch (x) {
case 1:
console.log(‘one’);
// missing break
case 2:
console.log(‘two’);
break;
default:
console.log(‘default’);
}
For x === 1, you get ‘one’, ‘two’, maybe ‘default’ if you miss the break at 2 too.
Double check every case and the default. Put break or return at the end of each block:
case 1:
doSomething();
break; -
Wrong value in switch expression
Log what you switch on:
console.log(‘switching on:’, myVar);
switch (myVar) {
…
}
Many times the bug is myVar is undefined or not what you think. -
Extra spaces or different strings
String cases must match exactly:
switch (status) {
case ‘OPEN’:
…
break;
case ‘CLOSED’:
…
break;
}
If status is ‘open’ or 'OPEN ’ you hit default.
Trim and normalize:
const statusNorm = String(status).trim().toLowerCase();
switch (statusNorm) {
case ‘open’:
…
break;
} -
Using expressions in case wrongly
This is wrong:
switch (x) {
case x > 10:
…
}
That compares x to true or false.
For ranges, use if/else:
if (x > 10 && x < 20) { … } -
Default in the middle and fallthrough
This works but confuses people:
switch (x) {
case 1:
…
default:
…
break;
case 2:
…
}
If you forget break above default, you hit default when you do not expect.
Keep default last while you debug.
Quick checklist for your code:
• Log the value you switch on and its type.
• Make sure all case values match type and content.
• Add break or return to every case and to default.
• Avoid boolean expressions inside case.
If you post the exact snippet, people can point at the exact failing line in about 10 seconds.
Couple more angles to check that haven’t been covered by @chasseurdetoiles:
-
switch(true)pattern vs plainswitch(value)
Sometimes people mix these up:switch (value) { case value > 10: // this NEVER does what you think }If you actually want range checks with
switch, it must be:switch (true) { case value > 10 && value <= 20: // ... break; case value > 20: // ... break; default: // ... }If your code mixes
switch(value)with booleancaseexpressions, you’ll hitdefaultall the time and think JS is broken. -
Hidden coercion before the switch
Even thoughswitchuses===, your value might already be coerced earlier:let status = someObj.status || '0'; // now it is always a string switch (status) { case 0: // never hit, because status is `'0'` break; }The fix is either change the
caseto'0'or normalize the value explicitly:const statusNum = Number(status); switch (statusNum) {I’d actually say “log typeof” as suggested is useful, but I disagree slightly: don’t just log it, assert it:
if (typeof value !== 'string') { throw new Error('Expected string in switch, got ' + typeof value); }That makes bugs scream instead of silently falling into
default. -
Asynchronous or changing value
If yourswitchis inside an async callback or event handler, sometimes the variable you switch on has changed by the time it runs:let code = 1; setTimeout(() => { switch (code) { case 1: // you *think* this runs break; default: // but maybe `code` was reassigned before timeout fires } }, 0); code = 3;Snapshot the value:
const current = code; switch (current) { ... } -
Object / array cases
If you’re doing something like:const val = { type: 'A' }; switch (val) { case { type: 'A' }: // never matches break; }That will always fall to
defaultbecause objects compare by reference, not structure. Same for arrays. Extract a primitive:switch (val.type) { case 'A': // works break; } -
Minimal repro as a sanity check
Take your broken switch and paste it into something like:const x = /* hardcode the value you *expect* to match */; console.log('x:', x, typeof x); switch (x) { case 'something': console.log('hit something'); break; case 123: console.log('hit 123'); break; default: console.log('hit default'); }If it works here but not in your real code, the issue is not the
switchsyntax at all, it is the data flow into it. In practice that ends up being “this variable isn’t what I think it is” about 95% of the time.
If you can post the exact snippet with 1 example input that should match but hits default, folks can usually point at the exact line that’s trolling you.