Learn TypeScript #3, Enumerations (Enums)

Transcript:

Hello, everybody! In our past videos we’ve talked about the most basic types in TypeScript, today I wanted to talk about enumerations (which you might also know as enums).

If you’re familiar with enumerations from other languages like C, C++, or any other language, they’re very similar in TypeScript, though there are a few differences that you’ll see as we go over their various features.

If you’re unfamiliar with enumerations (or if you don’t use them very often) the easiest way to think of them is as a group of related constants that are important to your program.

What this means in practice is that while you’re writing code you might find some mathematical constants that you need to use, or you might find that some piece of your code can be in several distinct states, and you need to represent that in some way.

Say if you’re writing a game, an enemy might be sleeping, or it might be patrolling, or it might be fighting, and you need to represent those different states with some sort of value. The exact value doesn’t necessarily matter, the most important thing is that you can tell each state apart from the other states. This is a great place to use an enum.

Using that example of an enemy in a game, we’re going to create a simple enum called EnemyState.

You can do that by using the enum keyword, then the name of the enum (EnemyState in this case), and then listing the names separated by commas within curly brackets.

A common convention when creating enums is for the members of the enum to be all upper case, with multiple words separated by underscores. However, there’s nothing forcing you to do that. If you perfer some other way of naming them, feel free to do so.

I mentioned moments ago that enums store constants, but I didn’t actually mention any values here, just names. So what value is used for EnemyState.SLEEPING?

Well, let’s create a variable storing that value, and then we’ll console.log() it.

I’ll open a terminal here and run it.

And we get 0! Okay, so we know TypeScript selected 0 for the value of SLEEPING.

Let’s change it to PATROLLING and see what it logs.

And we get 1!

So you can see that if we don’t specify any exact value, TypeScript will automatically use 0 as the starting number, and then work its way up one by one to 1, 2, 3 and so on.

One thing that’s helpful as well is that this EnemyState enum exists as an object at run time.

So, if you’re debugging something or you’re are working with a library that defines an enum and you’re asking yourself “hey what are the valid values of this particular enumeration?” you can simply log the enum object and see the possibilities.

You can see here when we logged it, though, we got more than just a list of values. We can see that the EnemyState enum maps between both the names and the values in both directions.

So if we had some random variable that came from an enum, and we wanted to see a human-readable version of the value, we can simply do EnemyState[x] and get the name of that member of the enum as a string.

If we open up the compiled .js file, you can see how they do this.

This might be a little weird to read at first, because they’re using a trick to save space, but read it from the inside out and it should make a little more sense.

Here they’re mapping between the name of the value and the value itself. And then it turns out that when you set something equal to something else, you can use that as an expression that returns the value that just got assigned. So they’re mapping the value back to the name, just like we saw in our tests previously.

It’s helpful to know at this point that you don’t need to let TypeScript automatically choose the numbers for you. You can add an equals sign to one of the members of the enum, and then all the values that follow will increment from there. You can also specify each value explicitly if that makes more sense for your program.

Now, let’s pause for a moment and compare enums to their alternatives.

The first and most obvious alternative would be to just declare a bunch of constants as normal variables, rather than as an enum. If you’ve only got a couple constants, or if none of the constants are related, that works just fine. But if they’re related, or you’ve got a situation like EnemyState where your main goal is to simply have a few distinct values, enums are the appropriate choice.

The second alternative, which you may have seen in a prior video, is union types.

As a refresher, a union type is a list of different types separated by the pipe character. You can then assign your variable to any of the types that are listed.

This is very much like an enum, and you’ll frequently see them used like enums in TypeScript code.

Enums have two main advantages over union types: First, since it’s all just numbers behind the scenes, they will be more efficient in some cases. Second, enums are available at run time as we’ve shown previously, so if you need a list of all possible values for debugging or display purposes, enums are a great option.

However, union types are quick to write and sometimes easier to think about, so often TypeScript code you see in the wild will prefer them over enums. Which is best to use will depend on your specific use case and your own personal preferences.

There’s a couple less-used features of enums that I wanted to show you before we wrap up.

First, your enums aren’t just restricted to numerical values, you can also put strings in them.

If we open the compiled JavaScript, you’ll see that there’s no longer any numbers being set. Just our enum member names being mapped to the strings we specified in TypeScript.

Back in the TypeScript code, you’ll see that if I remove one of the strings TypeScript gives me an error. Unlike numbers where TypeScript can just take whatever you did last and add a plus one to it, TypeScript has no idea what the next string is going to be. So, if you specify string constants you’re going to need to spell them all out.

Enums with strings in them aren’t used very often, but it’s a feature that’s available to you if you’ve got some string constants you need to group together.

The final feature I wanted to talk about are what’s called “const enums”. You can create one by simply putting the “const” keyword at the start of your enum declaration.

This has the effect of replacing all references to your enum with their literal values in the compiled JavaScript code. It also gets rid of the enum object. We’ll open up the compiled code, and you’ll see the enum has disappeared.

This will result in slightly more efficient code, at the cost of being harder to debug should you ever need to. Again, this is something you won’t see used very often, but it’s another tool to add to your toolbelt.

So that’s all there is to enums! I hope you enjoyed this video! If you would like to go deeper into TypeScript I’m producing a course called TypeScript By Example and you can find that at https://typescriptbyexample.com If you scroll down to the bottom you can put in your email address to be notified when the course is released.

Thank you so much for watching! I’ll see you in the next video.