How does the switch statement work?
The Short Answer
The switch statement evaluates an expression and matches its value against multiple case clauses using strict equality (===). When a match is found, it executes the code in that case block and all subsequent cases unless a break statement stops it (this is called "fall-through"). It's an alternative to long if...else if chains when you're comparing a single value against multiple known options. Switch is most useful when you have 3+ discrete values to check against.
Basic Syntax and Behavior
A switch statement has three key parts: the expression being evaluated, case labels to match against, and an optional default clause that runs when no case matches. Each case needs a break to prevent fall-through to the next case. The default clause is like the else in an if/else chain — it catches everything that didn't match.
function getStatusMessage(status: number): string {
switch (status) {
case 200:
return 'OK';
case 301:
return 'Moved Permanently';
case 404:
return 'Not Found';
case 500:
return 'Internal Server Error';
default:
return `Unknown status: ${status}`;
}
}
getStatusMessage(200) // 'OK'
getStatusMessage(404) // 'Not Found'
getStatusMessage(418) // 'Unknown status: 418'
// Equivalent if/else chain — more verbose with many cases:
function getStatusMessageIfElse(status: number): string {
if (status === 200) return 'OK';
else if (status === 301) return 'Moved Permanently';
else if (status === 404) return 'Not Found';
else if (status === 500) return 'Internal Server Error';
else return `Unknown status: ${status}`;
}
Fall-Through Behavior
Without a break (or return), execution "falls through" to the next case — it keeps running code until it hits a break or the end of the switch block. This is sometimes intentional (grouping multiple cases that share the same logic) but is often an accidental bug. Most linters flag fall-through without an explicit comment.
// ⚠️ Accidental fall-through — common bug
function getDayType(day: string): string {
let type = '';
switch (day) {
case 'Monday':
type = 'Start of work week';
// Missing break! Falls through to Tuesday's case
case 'Tuesday':
type = 'Regular work day';
break;
default:
type = 'Unknown';
}
return type;
}
getDayType('Monday') // 'Regular work day' — NOT what we wanted!
// ✅ Intentional fall-through — grouping cases
function isWeekend(day: string): boolean {
switch (day) {
case 'Saturday':
case 'Sunday':
return true; // Both cases share this return
default:
return false;
}
}
// ✅ Grouping with shared logic
function getQuarter(month: number): number {
switch (month) {
case 1: case 2: case 3:
return 1;
case 4: case 5: case 6:
return 2;
case 7: case 8: case 9:
return 3;
case 10: case 11: case 12:
return 4;
default:
throw new Error(`Invalid month: ${month}`);
}
}
Strict Equality Comparison
Switch uses strict equality (===) for comparisons — no type coercion happens. This means case '1' won't match the number 1, and case 0 won't match the string '0'. This is actually a benefit over loose comparisons, but it can surprise developers who expect type coercion.
const value = '1'; // string
switch (value) {
case 1: // number — won't match!
console.log('number 1');
break;
case '1': // string — matches
console.log('string 1');
break;
}
// Output: 'string 1'
// This also means null and undefined are distinct:
switch (null) {
case undefined: // won't match — null !== undefined
console.log('undefined');
break;
case null: // matches
console.log('null');
break;
}
Switch vs Object Lookup
For simple value-to-value mappings, an object (or Map) lookup is often cleaner than a switch statement. It's more concise, easier to extend, and avoids the fall-through footgun entirely. Use switch when you need complex logic per case (multiple statements, side effects). Use object lookups when each case just maps to a single value.
// Switch — verbose for simple mappings
function getColorName(code: string): string {
switch (code) {
case 'r': return 'Red';
case 'g': return 'Green';
case 'b': return 'Blue';
default: return 'Unknown';
}
}
// Object lookup — cleaner for value mappings
const COLOR_NAMES: Record<string, string> = {
r: 'Red',
g: 'Green',
b: 'Blue',
};
function getColorName(code: string): string {
return COLOR_NAMES[code] ?? 'Unknown';
}
// Use switch when cases have complex logic:
function handleAction(action: { type: string; payload?: unknown }) {
switch (action.type) {
case 'INCREMENT':
counter++;
logAnalytics('increment');
updateUI();
break;
case 'RESET':
counter = 0;
clearHistory();
break;
}
}
Why Interviewers Ask This
This is a fundamentals question that tests whether you understand fall-through behavior (and its risks), know that switch uses strict equality, can identify when switch is better than if/else or object lookups, and understand scoping within case blocks (variables declared in one case are visible in others unless you use braces).
Quick Revision Cheat Sheet
Comparison: Uses === (strict equality) — no type coercion
Fall-through: Without break, execution continues into the next case
Grouping cases: Intentional fall-through: case 'a': case 'b': return result
default clause: Catches unmatched values — like else in if/else
vs object lookup: Use objects for simple mappings, switch for complex per-case logic
Scoping tip: Wrap case bodies in {} if you declare variables to avoid scope leaks