All Articles

Using the Switch(true) Pattern in JavaScript

Using the Switch(true) Pattern in JavaScript

There’s a neat pattern that doesn’t seem to be well known. Until I joined the Application Development Team at Vortexa (we’re hiring), I hadn’t actually heard of it - but now I use it quite often. It’s called switch true and it’s really simple.

Basic Switch

Click here to skip the recap of the basic switch statement.

Most JavaScript developers are familiar with the switch statement (mdn docs), but for those who are newer to the language, let’s briefly go over it.

The switch statement lets you match an expression against one of a number of different cases:

const city = "London";

const getCountryByCity = () => {
  switch (city) {
    case "Edinburgh":
      return "Edinburgh is the capital city of Scotland";
    case "Madrid":
      return "Madrid is the capital city of Spain";
    case "London":
      return "London is the capital city of England";
    default:
      return "Cannot find which country this city is the capital of.";
  }
};

In this example, the expression (city variable) is matched against each case in the switch statement. If the case matches the result of the expression, the case will be executed - in this example it will return a string.

Switch (true)

The fundamental principle of the switch true pattern is that the switch statement will match against expressions as well as values. An expression in a case will be evaluated before matching. If the expression in your case evaluates to true - it will be matched.

switch (true) {
  case 1 + 1 === 2:
    // This case evaluates to true so it will be executed
    break;
  default:
    // This will not be executed
    break;
}

Why is this useful

This pattern can be used in so many different situations - often to replace complex if/else statements.

A common scenario this pattern becomes handy in is if you are validating data and have a set of criteria which will cause the validation to fail:

const user = {
  firstName: "Seán",
  lastName: "Barry",
  email: "my.address@email.com",
  number: "00447123456789",
};

if (!user) {
  throw new Error("User must be defined.");
}

if (!user.firstName) {
  throw new Error("User's first name must be defined");
}

if (typeof user.firstName !== "string") {
  throw new Error("User's first name must be a string");
}

// ...lots more validation here

return user;

This can be re-written using switch true like this:

const user = {
  firstName: "Seán",
  lastName: "Barry",
  email: "my.address@email.com",
  number: "00447123456789",
};

switch (true) {
  case !user:
    throw new Error("User must be defined.");
  case !user.firstName:
    throw new Error("User's first name must be defined");
  case typeof user.firstName !== "string":
    throw new Error("User's first name must be a string");
  // ...lots more validation here
  default:
    return user;
}

Both the if/else and the switch true can be written with the validation criteria abstracted for better readability:

switch (true) {
  case !isDefined(user):
    throw new Error("User must be defined.");
  case !isString(user.firstName):
    throw new Error("User's first name must be a string");
  case !isValidEmail(user.email):
    throw new Error("User's email address must be a valid email address");
  case !isValidPhoneNumber(user.number):
    throw new Error("User's phone number must be a valid phone number");
  // ...lots more validation here
  default:
    return user;
}

Summary

In my opinion this pattern offers cleaner readability when checking multiple conditions than lots of if/else blocks. I’m sure this will be quite polarising, but it’s always useful to be aware of these patterns so that they are available to be employed when appropriate.

If you have thoughts about this pattern - reach out to me on Twitter - @SeanBarryUK and let me know!