Mastering Typescript Enums

As a web developer, I’m constantly learning new ways to improve my coding practices. One of the more recent additions to my toolkit is TypeScript, a powerful superset of JavaScript that provides additional features to make coding easier and more efficient. One of my favorite features of TypeScript is enums, which allow me to better organize and define a collection of related values. In this article, I’ll dive deeper into TypeScript enums and show you how to use them effectively.

Introduction: What is TypeScript?

Before we dive into enums, let’s take a step back and talk about TypeScript itself. TypeScript is, as mentioned earlier, a superset of JavaScript. This means that it extends the functionality of the JavaScript language with additional features like classes, interfaces, and a static type system. TypeScript code is compiled into JavaScript, which means it can be used in any modern web browser or server environment.

At its core, TypeScript is designed to make writing JavaScript easier and more efficient. It provides tools to help catch errors early in the development process, and its typing system helps eliminate whole categories of bugs that are common in pure JavaScript. By using TypeScript, I can be more confident in the code that I write and more productive overall.

Defining Enums in TypeScript

Now that we’ve covered the basics of TypeScript, let’s move on to enums. An enum, short for enumeration, is a named collection of related values. In TypeScript, enums are defined using the enum keyword and can be defined in both numeric and string formats.

Here’s an example of defining a simple numeric enum:

enum Color {
  Red,
  Green,
  Blue
}

In this example, we’ve defined an enum called Color that has three possible values: Red, Green, and Blue. By default, each of these values is assigned an index starting at 0, so Red has an index of 0, Green has an index of 1, and so on.

Enums can also be defined with explicit index values, like this:

enum Color {
  Red = 1,
  Green = 2,
  Blue = 4
}

In this example, we’ve assigned explicit values to each of the enums. This can be useful in cases where you want to be sure that the value of the enum always matches a specific number.

Enum Values

There are three main types of enums in TypeScript: numeric enums, string enums, and heterogeneous enums. Each of these types has different use cases and can be useful in different situations.

Numeric enums

Numeric enums are the simplest type of enum in TypeScript. As the name suggests, numeric enums use numbers as their values. Here’s an example:

enum Direction {
  Up,
  Down,
  Left,
  Right
}

In this example, we’ve defined an enum called Direction that has four possible values: Up, Down, Left, and Right. By default, the Up value has an index of 0, Down has an index of 1, and so on.

Numeric enums can also be defined with explicit index values, like this:

enum Direction {
  Up = 1,
  Down,
  Left,
  Right
}

In this example, we’ve assigned an explicit value to the Up enum, and the other enums are assigned automatically starting from there.

String enums

String enums are similar to numeric enums, but they use strings as their values instead of numbers. Here’s an example:

enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

In this example, we’ve defined an enum called Direction that has four possible values: UP, DOWN, LEFT, and RIGHT.

String enums can be useful in cases where you want the value of the enum to be more descriptive. For example, you might use a string enum to represent different types of user roles or task states.

Heterogeneous enums

Heterogeneous enums are enums that have values of different types. Here’s an example:

enum Status {
  Pending = 1,
  Approved = "APPROVED",
  Rejected = { reason: "INVALID", code: 400 }
}

In this example, we’ve defined an enum called Status that has three possible values: Pending, Approved, and Rejected. The value of Pending is assigned the number 1, the value of Approved is a string, and the value of Rejected is an object.

Heterogeneous enums can be useful in cases where you want to store additional information along with the enum value.

Enum Methods

Now that we’ve covered the basics of defining enums, let’s talk about some of the methods that are available to use with enums in TypeScript.

The keyof operator

One useful method that you can use with enums in TypeScript is the keyof operator. This operator allows you to get a list of all the keys in an enum. Here’s an example:

enum Color {
  Red,
  Green,
  Blue
}

type ColorKeys = keyof typeof Color; // "Red" | "Green" | "Blue"

In this example, we’ve defined an enum called Color and used the keyof operator to get a list of all its keys. As you can see, the ColorKeys type ends up being a union of all the possible key names. This can be useful in cases where you want to iterate over all the possible values of an enum.

The for…in loop

Another useful method for working with enums is the for...in loop. This loop allows you to iterate over all the values in an enum and perform some action with each one.

enum Color {
  Red,
  Green,
  Blue
}

for (let key in Color) {
  console.log(key); // outputs "Red", "Green", "Blue", and potentially more
}

In this example, we’re using a for...in loop to iterate over all the values in the Color enum and log them to the console. One thing to note is that the for...in loop can also iterate over any additional properties that might be defined on the enum. So if you have an enum with an additional property like this:

enum Color {
  Red,
  Green,
  Blue
}

Color.Black = "#000000";

for (let key in Color) {
  console.log(key); // outputs "Red", "Green", "Blue", and "Black"
}

The for...in loop will also iterate over the Black property, even though it’s not technically an enum value.

Casting enums to other types

Finally, you can also use enums in conjunction with other TypeScript types by casting them to other types. Here’s an example:

enum Animal {
  Cat,
  Dog,
  Fish
}

interface Cat {
  type: Animal.Cat;
  name: string;
}

let myCat: Cat = { type: Animal.Cat, name: "Fluffy" };

In this example, we’re defining an interface for a Cat object, which includes a type property that is set to the Cat value of the Animal enum. We then create a new myCat object and set its type property to Animal.Cat.

Using Enums in TypeScript

Now that we’ve covered the basics of defining and working with enums in TypeScript, let’s talk about some of the ways that you can use enums in your actual TypeScript code.

Enum as function parameters

One common use case for enums is to use them as parameters for functions. For example, let’s say that we have a function that needs to know whether to sort a list of items in ascending or descending order. We could define an Order enum like this:

enum Order {
  Ascending,
  Descending
}

function sortItems(order: Order) {
  if (order === Order.Ascending) {
    // sort items in ascending order
  } else {
    // sort items in descending order
  }
}

In this example, we’re defining an Order enum with two values: Ascending and Descending. We then define a function called sortItems that takes an Order value as its parameter. Inside the function, we check to see whether the value is set to Ascending or Descending and sort the items accordingly.

Switch statements with enums

Another common use case for enums is to use them in switch statements. This can be useful in cases where you need to perform different actions based on the value of an enum. Here’s an example:

enum Color {
  Red,
  Green,
  Blue
}

function getColorName(color: Color) {
  switch (color) {
    case Color.Red:
      return "red";
    case Color.Green:
      return "green";
    case Color.Blue:
      return "blue";
  }
}

In this example, we’re defining an enum called Color with three possible values. We then define a function called getColorName that takes a color parameter of type Color. Inside the function, we use a switch statement to check the value of the color

parameter and return a string representing the color name if it matches one of the enum values.

Enums for constants

Enums can also be used to define constants in your TypeScript code. For example, let’s say that we have a maximum number of items that a user can add to their cart. We can define this maximum using an enum like this:

enum Cart {
  MaxItems = 10
}

In this example, we’re defining an enum called Cart with a single constant MaxItems that is set to 10. We can then use this enum in our code to enforce the maximum number of items that a user can add to their cart.

Conclusion

Enums are a powerful feature of TypeScript that allow developers to better define and organize related values. By using enums, you can improve the readability and maintainability of your code, and make it easier to catch errors early in the development process. Whether you’re using enums as function parameters, constants, or just to make your code more readable, they are a valuable tool that every TypeScript developer should be familiar with.

Typescript Declaration Merging
Typescript

Typescript Declaration Merging

Introduction Typescript Declaration Merging is an essential feature of the Typescript language, which allows developers to extend existing code without modifying it. It can be a bit complex and overwhelming for beginners, but once you understand how it works, you’ll find it to be a powerful tool. As a developer, you will come across scenarios […]

Learn Typescript Modules: Organization & Reusability
Typescript

Learn Typescript Modules: Organization & Reusability

As a developer, I am always looking for ways to make my code more organized and efficient. One tool that has helped me achieve this goal is Typescript modules. In this article, I will be discussing Typescript modules in-depth, including how to create and import them, how to declare dependencies, and the benefits of using […]

Learn Typescript Mixins: Avoid Spaghetti Code
Typescript

Learn Typescript Mixins: Avoid Spaghetti Code

As a software developer, I’ve been using Typescript for most of my latest projects. One of the most interesting features I’ve come across is Typescript Mixins. These allow for simple composability of classes and functions, which can help to reduce code complexity and improve maintainability. In this article, I’m going to provide a comprehensive guide […]