JavaScript match expression

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)

  1. 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.

  1. 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.

  1. 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})`
}
  1. 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()
}
  1. 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

Hi @Conrad

There is an existing official proposal for a match expression for JavaScript.

GitHub - tc39/proposal-pattern-matching: Pattern matching syntax for ECMAScript is the best place for discussions on the topic.

2 Likes