Skip to content

Pattern Matching

TypeScript’s switch matches on a single value. Python’s match/case (introduced in Python 3.10) is structural — it can destructure sequences, dictionaries, and class instances simultaneously. Think of it as TypeScript’s switch + array/object destructuring fused into one statement.

TypeScript
// TypeScript — switch + destructuring
const command = ["move", 10, 20];
if (Array.isArray(command) && command[0] === "move") {
const [, x, y] = command;
console.log(`Move to (${x}, ${y})`);
} else if (command[0] === "stop") {
console.log("Stopping");
} else {
console.log("Unknown command");
}
Python
command = ["move", 10, 20]
match command:
case ["move", x, y]:
print(f"Move to ({x}, {y})")
case ["stop"]:
print("Stopping")
case _:
print("Unknown command")
# Output: Move to (10, 20)

The case ["move", x, y] pattern checks the list length, checks that the first element equals "move", and binds x and y to the second and third elements — all in one step.

Mapping patterns match dictionary shapes, similar to TypeScript object destructuring in a switch.

TypeScript
// TypeScript — discriminated union pattern
type Event =
| { type: "click"; x: number; y: number }
| { type: "keypress"; key: string };
function handle(event: Event) {
switch (event.type) {
case "click":
console.log(`Click at (${event.x}, ${event.y})`);
break;
case "keypress":
console.log(`Key: ${event.key}`);
break;
}
}
Python
event = {"type": "click", "x": 100, "y": 200}
match event:
case {"type": "click", "x": x, "y": y}:
print(f"Click at ({x}, {y})")
case {"type": "keypress", "key": key}:
print(f"Key pressed: {key}")
case _:
print("Unknown event")
# Output: Click at (100, 200)

Class patterns destructure dataclass (or any class with __match_args__) instances.

TypeScript
// TypeScript — instanceof + destructuring
class Point { constructor(public x: number, public y: number) {} }
function describe(p: Point): string {
if (p.x === 0 && p.y === 0) return "Origin";
if (p.x === 0) return `Y-axis at ${p.y}`;
if (p.y === 0) return `X-axis at ${p.x}`;
return `At (${p.x}, ${p.y})`;
}
Python
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
point = Point(0, 5)
match point:
case Point(x=0, y=0):
print("Origin")
case Point(x=0, y=y):
print(f"On Y-axis at {y}")
case Point(x=x, y=0):
print(f"On X-axis at {x}")
case Point(x=x, y=y):
print(f"At ({x}, {y})")
# Output: On Y-axis at 5

You can add an if guard to any case arm — the equivalent of TypeScript’s conditional switch trick.

TypeScript
// TypeScript — no clean guard syntax in switch
function grade(score: number): string {
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
return "F";
}
Python
def grade(score: int) -> str:
match score:
case s if s >= 90:
return "A"
case s if s >= 80:
return "B"
case s if s >= 70:
return "C"
case _:
return "F"
print(grade(85)) # B
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
# Sequence pattern
for cmd in [["move", 5, 10], ["stop"], ["jump", 3], ["move", 0, 0]]:
match cmd:
case ["move", x, y]:
print(f" move -> ({x}, {y})")
case ["stop"]:
print(" stop")
case _:
print(f" unknown: {cmd}")
print()
# Mapping pattern
events = [
{"type": "click", "x": 10, "y": 20},
{"type": "keypress", "key": "Enter"},
{"type": "resize", "w": 800, "h": 600},
]
for evt in events:
match evt:
case {"type": "click", "x": x, "y": y}:
print(f" click ({x},{y})")
case {"type": "keypress", "key": k}:
print(f" key: {k}")
case {"type": t}:
print(f" other event: {t}")
print()
# Class pattern with guards
for pt in [Point(0, 0), Point(0, 7), Point(3, 0), Point(3, 4)]:
match pt:
case Point(x=0, y=0):
print(" origin")
case Point(x=0, y=y) if y > 0:
print(f" +Y axis at {y}")
case Point(x=x, y=0) if x > 0:
print(f" +X axis at {x}")
case Point(x=x, y=y):
print(f" quadrant ({x},{y})")
What Python version introduced structural pattern matching?
In `case ["move", x, y]`, what does `x` do?
How do you add a conditional check to a case arm?
What does `case _:` match?