Pattern Matching in JavaScript: The TC39 Proposal That Will Change Your Code
Hello HaWkers, one of the most anticipated proposals in TC39 is finally gaining traction: Pattern Matching for JavaScript. This feature, already present in languages like Rust, Scala, and Elixir, promises to revolutionize how we write conditional logic and data destructuring in JavaScript.
Have you ever been frustrated with endless if/else chains or confusing switch cases? Pattern Matching might be the solution you've been waiting for.
What is Pattern Matching?
Pattern Matching is a way to check values against patterns and extract data from complex structures declaratively.
Basic Comparison
Today with switch:
function getAnimalSound(animal) {
switch (animal.type) {
case 'dog':
return 'woof';
case 'cat':
return 'meow';
case 'bird':
return 'chirp';
default:
return 'unknown';
}
}With Pattern Matching (proposal):
function getAnimalSound(animal) {
return match (animal) {
when ({ type: 'dog' }) -> 'woof',
when ({ type: 'cat' }) -> 'meow',
when ({ type: 'bird' }) -> 'chirp',
else -> 'unknown'
};
}Why Does This Matter?
Benefits of Pattern Matching:
| Aspect | Traditional | Pattern Matching |
|---|---|---|
| Readability | Nested if/else | Declarative and clean |
| Destructuring | Separate from condition | Integrated |
| Exhaustiveness | Manual | Can be checked |
| Composition | Difficult | Natural |
| Types | Separate verification | Built into pattern |
The TC39 Proposal
Let's understand the details of the current proposal.
Status in TC39
History:
- Stage 1: 2020
- Stage 2: 2024
- Stage 3: Under discussion (2026)
- Stage 4: Expected 2027
Main champions:
- Mark Miller (Agoric)
- Tab Atkins (Google)
- Jordan Harband (Airbnb)
Proposed Syntax
The syntax is still under discussion, but the most likely version is:
// Basic syntax
match (value) {
when (pattern1) -> result1,
when (pattern2) -> result2,
else -> defaultResult
}
// As expression
const result = match (x) {
when (1) -> 'one',
when (2) -> 'two',
else -> 'other'
};Pattern Types
1. Literal Patterns:
const description = match (code) {
when (200) -> 'OK',
when (201) -> 'Created',
when (404) -> 'Not Found',
when (500) -> 'Server Error',
else -> 'Unknown Status'
};2. Object Patterns:
const message = match (response) {
when ({ status: 'success', data }) -> `Success: ${data}`,
when ({ status: 'error', message }) -> `Error: ${message}`,
when ({ status: 'loading' }) -> 'Loading...',
else -> 'Unknown state'
};3. Array Patterns:
const first = match (list) {
when ([]) -> 'Empty list',
when ([single]) -> `One item: ${single}`,
when ([first, second]) -> `Two: ${first}, ${second}`,
when ([head, ...tail]) -> `First: ${head}, rest: ${tail.length}`,
else -> 'Unexpected format'
};4. Patterns with Guards:
const category = match (user) {
when ({ age }) if (age < 13) -> 'child',
when ({ age }) if (age < 20) -> 'teenager',
when ({ age }) if (age < 60) -> 'adult',
when ({ age }) -> 'senior',
else -> 'unknown age'
};
Practical Use Cases
Let's see how Pattern Matching improves real code.
Processing API Responses
Before:
function handleResponse(response) {
if (response.status === 'success') {
if (response.data && response.data.items) {
return response.data.items.map(processItem);
} else if (response.data) {
return [processItem(response.data)];
} else {
return [];
}
} else if (response.status === 'error') {
if (response.code === 401) {
return redirectToLogin();
} else if (response.code === 404) {
return showNotFound();
} else {
return showError(response.message);
}
} else if (response.status === 'pending') {
return showLoading();
}
return null;
}With Pattern Matching:
function handleResponse(response) {
return match (response) {
when ({ status: 'success', data: { items } }) ->
items.map(processItem),
when ({ status: 'success', data }) ->
[processItem(data)],
when ({ status: 'success' }) ->
[],
when ({ status: 'error', code: 401 }) ->
redirectToLogin(),
when ({ status: 'error', code: 404 }) ->
showNotFound(),
when ({ status: 'error', message }) ->
showError(message),
when ({ status: 'pending' }) ->
showLoading(),
else -> null
};
}Reducers in State Management
Before (Redux-style):
function todoReducer(state, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, action.payload]
};
case 'TOGGLE_TODO':
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.payload
? { ...todo, completed: !todo.completed }
: todo
)
};
case 'DELETE_TODO':
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.payload)
};
default:
return state;
}
}With Pattern Matching:
function todoReducer(state, action) {
return match (action) {
when ({ type: 'ADD_TODO', payload }) -> ({
...state,
todos: [...state.todos, payload]
}),
when ({ type: 'TOGGLE_TODO', payload: id }) -> ({
...state,
todos: state.todos.map(todo =>
match (todo) {
when ({ id: ^id }) -> ({ ...todo, completed: !todo.completed }),
else -> todo
}
)
}),
when ({ type: 'DELETE_TODO', payload: id }) -> ({
...state,
todos: state.todos.filter(todo => todo.id !== id)
}),
else -> state
};
}
AST Parsing
Before:
function evaluate(node) {
if (node.type === 'NumberLiteral') {
return node.value;
} else if (node.type === 'BinaryExpression') {
const left = evaluate(node.left);
const right = evaluate(node.right);
if (node.operator === '+') {
return left + right;
} else if (node.operator === '-') {
return left - right;
}
}
throw new Error(`Unknown node type: ${node.type}`);
}With Pattern Matching:
function evaluate(node) {
return match (node) {
when ({ type: 'NumberLiteral', value }) ->
value,
when ({ type: 'BinaryExpression', operator: '+', left, right }) ->
evaluate(left) + evaluate(right),
when ({ type: 'BinaryExpression', operator: '-', left, right }) ->
evaluate(left) - evaluate(right),
else -> throw new Error(`Unknown node: ${JSON.stringify(node)}`)
};
}
How to Use Today
While the proposal is not approved, there are alternatives.
Current Libraries
1. ts-pattern (TypeScript/JavaScript):
import { match, P } from 'ts-pattern';
const result = match(value)
.with({ type: 'dog' }, () => 'woof')
.with({ type: 'cat' }, () => 'meow')
.with({ type: P.string }, ({ type }) => `${type} sound`)
.otherwise(() => 'unknown');2. match-iz:
import { match, when, otherwise } from 'match-iz';
const result = match(animal)(
when({ type: 'dog' }, () => 'woof'),
when({ type: 'cat' }, () => 'meow'),
otherwise(() => 'unknown')
);DIY with Functions
// Simple pattern matching implementation
function match(value) {
return {
when(pattern, result) {
const patterns = [{ pattern, result }];
const chain = {
when(p, r) {
patterns.push({ pattern: p, result: r });
return chain;
},
otherwise(defaultResult) {
for (const { pattern, result } of patterns) {
if (matches(value, pattern)) {
return typeof result === 'function' ? result(value) : result;
}
}
return typeof defaultResult === 'function'
? defaultResult(value)
: defaultResult;
}
};
return chain;
}
};
}
Timeline and Expectations
When can we expect Pattern Matching in production?
Estimated Roadmap
| Phase | Estimated Date | Status |
|---|---|---|
| Stage 3 | Q2 2026 | Under review |
| Browser implementation | Q4 2026 | After Stage 3 |
| Stage 4 | Q1 2027 | Pending |
| Available in Node LTS | Q3 2027 | Expected |
How to Prepare
1. Learn the concepts:
- Study Pattern Matching in other languages
- Practice with libraries like ts-pattern
- Understand advanced destructuring
2. Refactor existing code:
- Identify complex if/else chains
- Rewrite switches as pattern matches
- Document where you would use the feature
3. Follow the proposal:
- GitHub: tc39/proposal-pattern-matching
- Read TC39 meeting notes
- Participate in discussions
Conclusion
Pattern Matching is one of the most anticipated additions to JavaScript and has the potential to significantly transform how we write code. The feature brings more expressiveness, readability, and safety to conditional logic and data processing.
Key points:
- Pattern Matching allows checking values against patterns declaratively
- The proposal is at Stage 2 in TC39, moving toward Stage 3
- Supports literal, object, array patterns and guards
- Libraries like ts-pattern allow using similar concepts today
- Native availability expected between 2026-2027
For JavaScript developers, it's worth starting to familiarize yourself with the concept now. When the feature is released, you'll be ready to take full advantage of its potential.
For more on the future of JavaScript, read: ESM (ES Modules): Complete Adoption in JavaScript 2026.

