Enums are one of the few Typescript features that does not directly derive from Javascript. In this post, we will look at everything related to Typescript Enums and how you should use them in your applications.

In case you are new to Typescript, you can start with an Introduction to Typescript.

But what are Enums?

Enums help programmers define a set of constants by name. Once we define an enum, we can use that as a type of another variable. The only rule being that the variable can have a value only from one of the constants. This makes them really useful when we want to restrict the value of a variable to a certain group of possible values.

Let us now look at Typescript Enums in detail.

1 – Types of Typescript Enums

There are mainly three types of Typescript Enums we can use:

1.1 – Numeric Enums

Numeric enums are the most common type. We can define a numeric enum in Typescript as below:

enum Direction {
   East,
   West,
   North,
   South,
}

Looking at this, you might wonder where are the numbers?

When we declare an enum without specific string values, they automatically take numeric values. In this example, East gets a value of 0, West will get 1, North 2 and South will get 3.

Can we change the default numeric values?

Yes, we can do so quite easily. See below:

enum Direction {
   East=2,
   West,
   North,
   South,
}

In this case, we specifically assign the value of 2 to East. All of the following enum values are auto-incremented. In other words, West will have value 3, North has 4 and South has 5.

We can also assign specific numeric values to each item as well.

1.2 – String Enums

String Enums in Typescript are not so different from Numeric Enums. In a string enum, each member is initialized with a string literal or with another string enum member.

See below example of a String enum .

enum Direction {
   East = "EAST",
   West = "WEST",
   North = "NORTH",
   South = "SOUTH",
}

String enums don’t have auto-incrementing feature. However, they are better for serialization.

1.3 – Heterogenous Enums

We can mix numeric and string enum members in Typescript as below:

enum Direction {
   East = 1,
   West = "WEST",
   North = 3 ,
   South = "SOUTH",
}

However, this approach does not have useful use-case. Also, it may not be a good idea to use mixed enums.

2 – Constant vs Computed Values for Typescript Enums

The value of each enum member can be constant or computed.

However, there are a few rules associated with this. An enum member is constant in the below cases:

  • It is the first member in the enum and there is no initializer. Basically, the value for the enum member is 0 in this case. In the below example, the value of North is 0.
enum Direction {
    North
}
  • It does not have an initializer but the preceding enum member is a numeric constant. In such a case, the value of current member will be auto-incremented by 1. For the below example, the values are in sequence starting from 0 and ending at 3.
enum Direction {
    North,
    West,
    South,
    East
}
  • The enum member is initialized with a constant enum expression. Constant enum expressions cannot evaluate to NaN or Infinity.

A computed enum member in Typescript can look as below:

enum Direction {
   North = "North".length
}

We can also have a combination of constant and computed enum members in a particular Enum set.

3 – Typescript Enum Members as Types

Enum members in Typescript can also become types as well.

See below example:

enum Genre {
   Fantasy,
   SciFi
}

interface FantasyBook {
   title: string,
   genre: Genre.Fantasy
}

In this case, we declare that for any object of type FantasyBook can only have genre of type Fantasy. Use of any other enum member will throw a compilation error as per the Typescript type system.

4 – Reverse Mapping from Value to Enum

So far we have looked at examples of having a value from the enum member.

However, it is also possible to have a reverse mapping from enum values to the actual enum names.

See the below example:

enum Direction {
   Left,
   Right
}

let direction = Direction.Left; //assign 0 to direction
let directionName = Direction[direction]; //this will give "LEFT"

This is possible because an enum is ultimately compiled into an object that stores both forward and reverse mappings. However, important point to note is that this is applicable only for numeric enums. String enums do not get a reverse mapping.

5 – Objects vs Typescript Enums

An important argument against enums in Typescript is that objects can do the same thing as an enum. In fact, Typescript enums are also internally handled as objects after transpilation.

Let’s see their usage on a comparative level.

const enum EDirection {
  North,
  South,
  East,
  West,
}
 
const ODirection = {
  North: 0,
  South: 1,
  East: 2,
  West: 3,
} as const;

//Using Enum
function go(dir: EDirection) {}
 
//Using Object
type Direction = typeof ODirection[keyof typeof ODirection];
function travel(dir: Direction) {}
 
walk(EDirection.Left);
run(ODirection.Right);

As you can see, we need some extra logic when using the types from an object as arguments. With enum, the type system works out-of-the-box.

However, since enums are currently a Typescript feature, our code is not exactly aligned with current state of Javascript if we use enums. Regardless, enums do provide some good syntactical capabilities.

6 – Convert Typescript Enums to Array

Many times we use enums to describe a certain type of data. However, we may also need to use those types elsewhere.

For example, if we have an enum for Genre of a book, we might want to show the members in a dropdown list. In such a case, we can convert Typescript Enums to an Array.

See below example for the same:

export enum Genre {
  Fantasy,
  SciFi
}

export const GenreList: {
  value: string;
}[] = Object.values(Genre)
  .filter((value) => typeof value === "string")
  .map((value) => ({ value: value as string }));

This will output the genre list as follows:

[{"value":"Fantasy"},{"value":"SciFi"}]

Basically, the Typescript Enum is now converted to a normal array. We can do further operations upon it as needed.

7 – Check if Value Exists in Typescript Enum

Another common use-case is to find whether a particular value is existing in a Typescript enum or not.

For example, if we want to check whether Fantasy genre is present in our list of valid genres. This can be done as follows:

enum Genre {
    Fantasy='fantasy',
    SciFi='scifi'
}
  
function isValidGenre(genre: string): boolean {
    const options: string[] = Object.values(Genre);
    return options.includes(genre);
}

console.log(isValidGenre('fantasy'))

This will print true. If you see a warning in the editor, you need to compiler option in tsconfig.json to target ES2017.

"lib": ["es2017"]

You can read more about the role of tsconfig file in this detailed post about Typescript tsconfig.

Conclusion

In this post, we have taken a comprehensive look at Typescript enums, their various types and applications for different situation. While enums in Typescript are not aligned with the state of Javascript, they are a handy feature for certain situations.

Want to learn more about how Typescript differs from Javascript? Check out this detailed comparison post.

If you have any comments or queries about this post, please feel free to mention in the comments section below.

Categories: Typescript

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *