I think the post doesn't give a fair comparison as in the if/else case there's no need to use "else" blocks if you're throwing an error or returning. In this case I think simple "if" statements are cleaner and certainly more "normal".

E.g.

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

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

  return user;

When validation gets complex (e.g. there are many criteria to check), I like to build a list/stream/array (what ever the language offers) of tuples of predicates (functions from the object that gets validated to boolean) and strings (or functions from the object to string so I can have context in my error messages).

Then iterate over the tuples, if a predicate fails, return the associated error message and throw an error/display the message to the user.

In the end it looks something like this:

  var validators = Stream.of(
    Map.entry(user -> user != null, "User must be defined"),
    Map.entry(user -> user.firstName != null, "Missing first name"))

  validators.filter(e -> e.getKey().apply(userToBeValidated)).map(Map.Entry::getValue).getFirst()
(This example uses Map.entry for tuples as Java lacks native support for tuples)

This limits branching and you have all validation criteria neatly organized in the same location.

Sure, if you're validating some data there're loads of better ways to do it than a bunch of conditionals. I was purely commenting on the switch(true) pattern vs some "if"s.

That approach looks nice though. On that subject, JS has some nice libraries including io-ts[1] which has a functional approach using Eithers to encapsulate errors/success.

[1]: https://github.com/gcanti/io-ts