Rahul Chhodde I'm a software developer with over seven years of experience in different web technologies.

Evaluating alternatives to TypeScript’s switch case

5 min read 1656

Evaluating Alternatives to TypeScript’s Switch Case

Switch case statements are attracting attention in the programming community for their drawbacks. Some developers claim that the verbosity and bulkiness of switch cases are reasons to abandon using them entirely. However, are switch case statements that bad?

This article will discuss the pros and cons of TypeScript’s switch case, cover some alternatives, and look at which alternatives are best for various use cases.

Jump ahead:

What is a switch case statement?

A switch case block is a control structure that performs different actions according to outputs provided by given conditions. In JavaScript, the switch keyword of a switch case block needs a condition to evaluate. In contrast, the other statements inside the block represent possible outcomes or cases of that condition and their associated actions.

When a match is found, the statements associated with that match execute. The default statement executes if no match is found, and the control leaves the switch case block.

Because TypeScript is a superset of JavaScript, most of the processes will stay the same, except for some type introductions.

The example below explains switch case usage in TypeScript:

 const vitamin: string = "A";

switch(vitamin.toLowerCase()) {
  case "a":
    console.log("Spinach, Carrots, Sweet Potatoes, Mango");
    break;
  case "b":
    console.log("Meat, Fish, Milk, Cheese, Eggs.");
    break;
  case "c":
    console.log("Oranges, Kiwi, Lemon, Strawberries, Tomatoes");
    break;
  default:
    console.log("No sources available.");
    break;
}

Switch Cases in TypeScript

See this example in the TypeScript Playground.

In the code above, we added a string type to the variable Vitamin, which represents the type-safe nature of TypeScript.

TypeScript switch case pros

Switch case blocks serve as substitutes for lengthy, nested if-else statements. Although there are alternatives, switch cases still have some advantages:

  • Elegance: TypeScript switch cases are more elegant and easier to read than if-else blocks
  • Performant: Switch cases are more performant and are faster to execute than if-else
  • Small-scale maintainability: Switch cases offer better maintainability than lengthy if-else blocks

Despite their superior performance to if-else blocks switch case statements don’t look as impressive in advanced scenarios. Considering the modern-day software development process, switch cases have significant downsides.

TypeScript switch case cons

While there is nothing wrong with the utility of switch cases, the real pain for developers is misapplying them, which is likely to occur because of the underlying problems of switch cases:

Verbosity

Developers nowadays tend to avoid verbosity in their code. Take a look at the following code block for an example of how switch cases lead to more verbose code:

const day: number = 1;
switch (day) {
  case 1: console.log("Monday");
    break;
  case 2: console.log("Tuesday");
    break;
  case 3: console.log("Wednesday");
    break;
  case 4: console.log("Thursday");
    break;
  case 5: console.log("Friday");
    break;
  case 6: console.log("Saturday");
    break;
  case 7: console.log("Sunday");
    break;
  default: console.log("Invalid Input !!!!");
}

In the code above, the repeated use of case and break makes the code bulky and lengthy.

Error-prone

Missing break keywords in switch case clauses lead to frustrating errors. Although it may not appear serious in minor projects, these errors can cause severe bugs in projects with huge codebases.

The error-prone nature of switch case blocks makes them less useful in large projects and ultimately less appealing to developers.

Poor large-scale maintainability

Although switch cases have better maintainability in smaller projects than if-else statements, their bulkiness and error-prone behavior damage their maintainability. Switch case statements are known to deteriorate code maintainability as projects grow.

Nowadays, developers prefer to use alternatives to switch cases to keep their codes more readable and maintainable.

Using the object lookup table as an alternative to TypeScript’s switch case

In JavaScript and TypeScript, object lookup is the most common method for avoiding switch cases. This technique uses an object literal like a table, with possible cases and their associated actions, and consumes it:

const vitamin: string = "A",
      defaultSource = "No sources available."

const sources: { [key: string]: string; } = {
  "a": "Spinach, Carrots, Sweet Potatoes, Mango",
  "b": "Meat, Fish, Milk, Cheese, Eggs", 
  "c": "Oranges, Kiwi, Lemon, Strawberries, Tomatoes",
};

console.log(sources[vitamin.toLowerCase()] || defaultSource);

Using the Object Lookup Alternative to Switch Cases in TypeScript

See this example in the TypeScript Playground.

That looks much neater and easier compared to using a switch case block.



The most significant point of the object lookup technique is that, unlike switch case blocks, they don’t require adding a break for every case. This prevents you from missing breaks and causing bugs, which is helpful when working on a big codebase.

Object lookup tables are less verbose, easily readable, and easily scanned. Although this alternative to switch cases has benefits, it also has time and memory tradeoffs.

The object lookup approach might not be as fast as switch cases when there aren’t many cases to evaluate. Since an object is a data structure, accessing keys would require more work than simply checking values and returning them, as we do with the switch case.

A JavaScript object is cached in memory and later cleared by the garbage collector as soon as the object scope ceases to exist. More object keys take more memory and add to the space complexity.

It is always a good idea to test the performance of big object tables before finalizing their usage in your project.

Examining the benefits of polymorphism and inheritance

Even though switch cases don’t have memory limitations, they are hard to maintain. As the project grows, adding more cases and missing one break leads to big problems, including violating the open-closed principle of SOLID software design.

To understand how switch cases are prone to violating the open-closed principle, let’s look at this example:

enum Vitamin {
  A,
  B,
  C
};

class VitaminHelper {
  public sources(vitamin: Vitamin) {
    switch(vitamin) {
      case Vitamin.A: 
        return "Spinach, Carrots, Sweet Potatoes, Mango";
      case Vitamin.B: 
        return "Meat, Fish, Milk, Cheese, Eggs";
      case Vitamin.C: 
        return "Oranges, Kiwi, Lemon, Strawberries, Tomatoes";
      default:
        return "No sources available.";
    }
  }  

  public symptoms(vitamin: Vitamin) {
    switch(vitamin) {
      case Vitamin.A: 
        return "Dry eyes, dry skin, frequent infections";
      case Vitamin.B: 
        return "Anaemia, fatigue, or poor balance, memory loss";
      case Vitamin.C: 
        return "Bruising, coiled hair, failure to thrive, irritability";
      default:
        return "No deficiency symptoms available.";
    }
  }
}

TypeScript Switch Case Alternative With Polymorphism and Inheritance

See this example in the TypeScript Playground.

For simplicity, I’ve avoided using the break keyword in the example and used return instead.

The code above shows the use of enum in the VitaminHelper class has two methods to handle the vitamin sources and the deficiency symptoms.

Both ways implement the switch case with the Vitamin to determine the cases and take the appropriate actions. We must modify both methods if we add a few more vitamin values to the enum.

Implementing similar patterns of switch case statements across large projects adds to poor maintainability and opens the entities to modifications — violating the open-closed principle of software design.

In the above example, if we replaced the switch case with an object table, each method would still need to be updated whenever a new object key is added. It won’t solve the maintainability problem.

Better maintainability with OOP

TypeScript supports the OOP paradigm of programming, which helps create more robust and maintainable code without using switch cases or object lookup tables. Let’s examine polymorphism and inheritance in OOP as alternatives to switch case blocks in TypeScript.

Inheritance allows us to derive a class from an existing base class. With polymorphism, we can change the behavior of the existing members of the base class. Let’s use these concepts to fix the poor maintainability of our current code.

First, we need to drop the scoped enumerations and write an abstract class that includes two methods we will inherit in subsequent classes:

abstract class Vitamin {
  public sources() { /* Default sources */ }
  public symptoms() { /* Default symptoms */ }
}

Following the polymorphism and inheritance concepts, we can write different classes for extending our base class and overriding its default methods:

class A extends Vitamin {
  public sources() {
    return "Spinach, Carrots, Sweet Potatoes, Mango";
  }
  public symptoms() {
    return "Dry eyes, dry skin, frequent infections";
  }
}
class B extends Vitamin {
  public sources() {
    return "Meat, Fish, Milk, Cheese, Eggs";
  }
  public symptoms() {
    return "Anaemia, fatigue, or poor balance, memory loss";
  }
}
class C extends Vitamin {
  public sources() {
    return "Oranges, Kiwi, Lemon, Strawberries, Tomatoes";
  }
  public symptoms() {
    return "Bruising, coiled hair, failure to thrive, irritability";
  }
}

Now, whenever a new Vitamin is introduced, we can repeat the process above and write a new Vitamin association that extends our base class.

class D extends Vitamin {
  public sources() {
    return "Sunlight, Salmon, sardines, red meat, egg yolks";
  }
  public symptoms() {
    return "Fatigue, bone pain or achiness, hair loss";
  }
}

Example of TypeScript Switch Case Alternatives in Action

See this example in the TypeScript Playground.

In the example above, the inheritance property of OOP in TypeScript allowed us to repeat the behavior of a base class in different child classes. Classes A, B, and C are child classes of Vitamin and inherit all its properties.

Polymorphism helped us change the form and behavior of our base class. This was demonstrated when overriding or redefining the sources() and symptoms() methods in each child class.

Unlike switch case statements, which require us to modify existing classes constantly, polymorphism avoids this and is more maintainable and easier to understand.

We can now define a child class that extends the base class Vitamin and overrides its behavior whenever a new Vitamin value needs to be introduced.

Conclusion

We learned about TypeScript’s switch case statements, the troubles they may cause, and some of their alternatives. Switch case statements are not harmful to small hobby projects, but it’s easier to use alternatives to avoid switch cases as your project grows.

If memory is not a concern, the object lookup technique is a great alternative to switch cases. For projects with the potential to grow, it is best to use polymorphism and inheritance to specify different cases clearly and keep maintainability.

I hope you enjoyed reading the article. Let me know your thoughts in the comments.

: Full visibility into your web and mobile apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

.
Rahul Chhodde I'm a software developer with over seven years of experience in different web technologies.

Leave a Reply