Currently, JavaScript lacks a powerful pattern matching mechanism.
Although there is a switch statement, it has many problems: it needs explicit break, its scope is confused, and it can only make simple===comparisons.
Although the existing TC39 pattern matching proposal has solved some problems, we think we can get more inspiration from Rust's design.
Proposal grammar design
javascript
// Basic grammatical structure
const result = match (value) {
// Literal matching
1 => "one",
2 => "two",
// Range matching (refer to Rust's
.=syntax)
3..=9 => "single digit",
// Matching with conditional guards
n if n > 10 && n < 20 => "teen",
// Multi mode (using the | operator)
20 | 30 | 40 => "round number",
// Structure deconstruction matching
{ type: "user", name, age } if age >= 18 => `Adult: ${name}`,
{ type: "user", name, age } => `Minor: ${name}`,
// Array mode
[first, ...rest] if rest.length > 0 => `Array with ${rest.length + 1} items`,
[] => "Empty array",
// Type matching (using built-in type checking)
String => "It's a string",
Number if value > 0 => "Positive number",
// Default branch (must be the last)
_ => "Something else"
};
Key characteristics (learn from Rust)
- Exhaustive inspection
The match expression must handle all possible situations, and the first matching branch will be executed.
The Rust ReferenceThe Rust Programming Language In JavaScript, we recommend that if the default branch (_) is not provided, and the compiler/runtime cannot determine that all situations are overwritten, an error should be thrown.
- Expression instead of statement
Different from the switch statement, match is an expression that can return a value, which makes the code more functional and concise.
- Mode guard
The pattern guard further refines the matching conditions by adding if conditions after the pattern.
javascript
match (point) {
{ x, y } if x === y => "On diagonal",
{ x, y } if x === 0 => "On Y axis",
{ x, y } if y === 0 => "On X axis",
{ x, y } => `Point at (${x}, ${y})`
}
- Deconstruction ability
Support deep nesting deconstruction, including objects, arrays, and mixed structures:
javascript
match (response) {
{
status: 200,
data: { user: { name, email } }
} => handleSuccess(name, email),
{
status,
error: { message }
} if status >= 400 => handleError(message),
_ => handleUnexpected()
}
- Binding variables
Use the @ symbol to bind the entire value while matching:
javascript
match (value) {
arr @ [_, _, _] => `Three element array: ${arr}`,
obj @ { type: "special", ...rest } => processSpecial(obj),
_ => "other"
}
Features:
Syntax conciseness: use=>instead of:, more in line with the style of JavaScript arrow functions
Range mode: supported
.=syntax for range matching
Stronger type integration: constructors can be directly used as type patterns
Must be exhaustive: it is mandatory to deal with all situations to improve code security