Why Developers Still Write if/else When match Feels Better

Why Developers Still Write if/else When match Feels Better
Photo by Liubomyr Vovchak / Unsplash

When you first discover functional-style pattern matching in JavaScript or TypeScript — something like:

match({
  A: (a) => handleA(a),
  B: (b) => handleB(b),
})(props)

—it’s hard not to wonder: why are people still writing endless if/else or switch statements? The elegance of a declarative match approach can feel like a breath of fresh air. But in practice, the story is a bit more nuanced. Let’s explore the reasons why if/else dominates, and where match truly shines.


The Comfort Zone: Familiarity and Readability

Most developers learned programming with imperative control flow: if/else, switch, for, while. These constructs are ingrained in almost every mainstream language.

  • Onboarding new developers: A junior engineer may find if/else easier to follow than an unfamiliar match abstraction.
  • Code reviews: Teams often prioritize clarity for the average reader over elegance. A switch block is predictable; a custom match function needs explanation.

Readability is cultural. What looks clean and obvious to a functional programmer can look cryptic to someone without that background.


Tooling, Debugging, and IDE Support

Tooling ecosystems are still better aligned with traditional branching.

  • Autocomplete works naturally inside if/switch blocks.
  • Linters and formatters enforce rules more consistently there.
  • Debugging stack traces is often clearer: if/else shows a simple line number, while match may introduce anonymous functions and wrappers.

When you’re working under tight deadlines, better tooling support often trumps elegance.


Flexibility: Complex Conditions

match works beautifully for discrete cases (enums, tagged unions, prop variants). But what about logic like:

if (x > 10 && y < 5 && user.isActive) {
  …
}

Pattern-matching expressions can become awkward or verbose here. In contrast, if/else is designed for boolean logic without ceremony. This flexibility keeps it relevant.


Performance and Predictability

For small cases, performance differences are negligible. But in tight loops or hot paths:

  • if/else and switch can be optimized by JS engines into efficient jumps.
  • match typically adds object lookups and function calls.

Even if the real-world impact is small, some teams default to primitives for predictable performance.


The Weight of Ecosystem Inertia

Open any JavaScript tutorial, read most style guides, or look at Stack Overflow answers: you’ll find if/else everywhere. Developers stick with what’s “normal,” especially in team settings where unconventional code can raise eyebrows.

This inertia matters. Even if match is “better,” convincing a team to adopt a different mental model can be an uphill battle.


The Rise of Pattern Matching in JavaScript

It’s worth noting that pattern matching is coming to JavaScript. TC39 (the committee behind JS standards) has a proposal for native syntax like:

match (value) {
  when { type: "A", data } => handleA(data),
  when { type: "B", data } => handleB(data),
  else => handleDefault()
}

When that lands, the argument for if/else weakens. But until then, most developers either don’t know about libraries like ts-pattern, or avoid them to reduce dependencies.


The Real Killer Feature: Exhaustiveness Checking

Here’s where match truly wins in TypeScript:

type Shape = { kind: "circle", radius: number }
           | { kind: "square", size: number };

match(shape)
  .with({ kind: "circle" }, (c) => …)
  .with({ kind: "square" }, (s) => …)
  .exhaustive(); // ✅ ensures all cases are handled

With if/else, TypeScript won’t complain if you forget to handle square. With match, you get type-checked safety. This prevents entire classes of bugs.


Other Considerations You Might Be Missing

  1. Team Culture: A “clever” match may get rewritten in review if your team values consistency over novelty.
  2. Error Handling: With if/else, it’s obvious where the else goes. With match, forgetting a default handler can cause runtime errors.
  3. Learning Curve: Not everyone on the team may understand functional abstractions, leading to accidental misuse.
  4. Future-Proofing: Betting on proposals or third-party libraries means you must maintain them. if/else will never disappear.

So, Which One Should You Use?

  • Use if/else for quick, ad-hoc conditions or when working in codebases with mixed experience levels.
  • Use match when handling discriminated unions, enums, or structured props, especially in TypeScript where exhaustiveness matters.
  • Avoid dogma. Both tools have their place, and the best engineers know when to reach for each.

Finally

Once you experience declarative match, if/else can feel primitive. But in the real world, factors like familiarity, tooling, flexibility, and inertia keep if/else alive.

The real shift will happen once JavaScript itself supports pattern matching natively. Until then, you’re likely to see both coexist — with if/else as the safe, universal option, and match as the more elegant but niche choice.

Elegance vs. familiarity. Safety vs. simplicity. That’s the balance every developer has to strike.

Support Us