If you’re coming from a functional programming language such as Elixir, Haskell or ReasonML, you may know how frustrating is to switch to a language which does not support pattern matching natively.

Once you start to approach problem using pattern matching, you’ll never go back to the messy if/else if/ else statements!

Let’s see what I’m talking about, coding the famous FizzBuzz interview question in both ReasonML and plain JavaScript:

let fizzBuzz = (i: int): string =>
  switch (i mod 3, i mod 5) {
    | (0, 0) => "FizzBuzz"
    | (0, _) => "Fizz"
    | (_, 0) => "Buzz"
    | (_, _) => string_of_int(i)
  };

for (i in 1 to 100) {
  fizzBuzz(i) |> Js.log
}

So as you can see in the ReasonML implementation above, we’re using a switch statement which pattern matches agains a tuple, returning the desired output on specific conditions.
I’ll explain for you how does it work, just in case you’re not familiar with ReasonML:

  1. On line 1, we define a new function which takes an integer i as a parameter and returns a string. Pretty similar to TypeScript, isn’t it?
  2. On line 2 we declare a switch statement, which works similarly to the JavaScript switch. In that case, we’re switching against a tuple, which is a ReasonML immutable, ordered and fix-sized data structure that contains two integers: the result of i % 3 and the result of i % 5. (mod stays for the modulo operator).
  3. On line 3, we check if the tuple matches the declared condition, just like a JavaScript case statement. If the tuple is (0, 0) (so the number is evenly divisible by 15), we return "FizzBuzz". Otherwise we continue with the next statement.
  4. On line 4, we check if the given tuple is equal to (0, _), where the underscore means “any value”. So, if the given parameter i is evenly divisible just by 3, we return "Fizz", and so on with the other statements.

So, what about JavaScript? How can we implement a similar solution, given that we don’t have any native pattern matching implementation?

function fizzBuzz(i) {

  const [x, y] = [(i % 3), (i % 5)];

  switch (true) {

    case (x === 0 && y === 0):
      return "FizzBuzz";

    case (x === 0):
      return "Fizz";

    case (y === 0):
      return "Buzz";

    default:
      return String(i);
  }

}

for(let i = 1; i < 100; i++) {
  console.log(fizzBuzz(i));
}

Believe it or not, this is the closest ReasonML to JavaScript implementation I came up with!
Let’s break it down:

  1. On line 3, we use the ES6 Destructuring Assignement in order to get an array containing just two values (x and y) where x is the result of i%3 and y is the result of i%5.
  2. At time of writing, the only real alternative to pattern matching in JavaScript is the switch/case control structure, testing agains the true boolean value. So we use that switch/case to check if our value i should return FizzBuzz, Fizz and so on.

This is not the most elegant solution for the FizzBuzz challenge, but I hope that it allowed you to understand what pattern matching is and why we need it!

The Proposal

function fizzBuzz(i) {
  
  case ([(i % 3), (i % 5)]) {
    when [0, 0] -> return "FizzBuzz";
    when [0, _] -> return "Fizz";
    when [_, 0] -> return "Buzz";
    when _      -> return String(i);
  }

}

for(let i = 1; i < 100; i++) {
  console.log(fizzBuzz(i));
}

And here it is, the FizzBuzz solution using the Pattern Matching Proposal!
It looks incredibly similar to the ReasonML solution, doesn’t it?
In JavaScript we don’t have tuples, so we still use arrays, but look at the code: we don’t even need to destructure our array and get x and y values!
Just like in ReasonML, OCaml, Elixir etc, we use the underscore as a “catch-all” character.

  1. On line 3 we define our new case statement, which accepts any kind of value as argument. In that case, we pass in just an array with two integers.
  2. On line 4, we check if the array we previously passed to the case statement is equal to [0, 0]. If that is the case, we return "FizzBuzz".
  3. On line 5, we check if the first element of our array is equal to 0. We don’t mind about the second element, which can be literally anything. Same for the next cases.

Data Fetching

async function getData() {
  const response = await fetch("https//yesno.wtf/api");

  case (response) {
    when { status: 200 } -> return "Data successfully fetched!";
    when { status: 404 } -> return "Endpoint not found!";
    when { status } if (status >= 400) -> {
      return "We got an error while fetching data"
    }
  }
}

(async () => console.log(await getData()))();

Let’s pretend we need to call a REST API service, and we need to check the response status code.
It’s a perfect task for our new pattern matching friend! We can pattern match against our fetch response and return the informations we need.

React and JSX

<Fetch url={API_URL}>
 {
   props => case (props) {
     when { loading } -> <Loading />
     when { error }   -> <Error error={error} />
     when { data }    -> <Page  data={data}   />
     when _           -> throw new Error('bad match')
   }
 }
</Fetch>

Mixing the newest case control structure with JSX is really an amazing way to explore its potential. It really helps loading the right component and adds an extra layer of safety thanks to the _ (catch-all) char! With it, you can both throw a new error, or load a “generic-error-component” without causing runtime exceptions.

Using Pattern Matching Today

At time of writing (May 2019), the Pattern Matching proposal is in stage-1, so you can use it thanks to Babel!

Did you like this article? Consider becoming a Patron!

This article is CC0 1.0 (Public Domain) licensed.