TypeScript Up & Running: Enums

Mouafa Ahmed
codessert
Published in
6 min readSep 22, 2016

--

In the previous article we mentioned that Typescript offers different ways of creating custom types, and Enums is one of them.

This article will cover Enums, the usage & the benefits

The Problem

For this article we’ll write a job application management, well that looks too big. But don’t worry we will only write a small chunk of the app which holds the logic to determine the state of the job application. So let’s say that Sami applied to the Acme Inc job offer, his application will be managed according to those states:

  1. Applied: Acme Inc just received Sami application
  2. Interview: Acme Inc decided to interview Sami
  3. Hired: Acme Inc hired Sami
  4. Rejected: Acme Inc rejected Sami

For each state we associate a status code, like this

1 <-> applied
2 <-> interview
3 <-> hired
4 <-> rejected

So to describe an application with the Applied state, it should look like this,

var application = {
name: 'Sami Najar’,
status: 1
}

If we want to change the application status to interview, we simply do this,

application.status = 2

And to change it to hired we do this,

application.status = 3

You can notice that we don’t care anymore about the state, we only care about its status code. But wait what if we step ahead from this code for a couple months and then we come back to it, would we still remember what those status codes means!

Well we may think for a simple solution, like this

var status = {
applied: 1,
interview: 2,
hired: 3,
rejected: 4
}

Then we can change the status like this

application.status = status.hired

Well this was a hot fix, but what if we want to get the state name from the status code? or what if we want to hide the status codes meaning in our run time code? Well we need another solution!

Introducing Enums

Enums is the feature that let Typescript handle two way data mappings.

Let’s start by converting status Object to State Enum

const enum State {
applied = 1,
interview = 2,
hired = 3,
rejected = 4
}

Notice that we use ‘=’ rather than ‘:’ for assigning value

So this Enum will generate this javascript code

var State;
(function (State) {
State[State["applied"] = 1] = "applied";
State[State["interview"] = 2] = "interview";
State[State["hired"] = 3] = "hired";
State[State["rejected"] = 4] = "rejected";
})(State || (State = {}));

So what this code means?, well it create a lookup object, looks like this,

State = {
1: "applied",
2: "Interview",
3: "hired",
4: "rejected",
applied: 1,
interview: 2,
hired: 3,
rejected: 4
}

So what make this object so helpful?, well this object store both forward and backward mapping:

  • Forward Mapping (name -> value), so if we have the name and need the corresponding value, we can get it like this
var name = 'hired'
var value = State[name] // return 3
  • Backward Mapping (value -> name), also called Reverse Mapping because it’s the reverse of Forward Mapping, So if we have the value and need to get the associated name, this will do the job
var value = 3
var name = State[value] // return 'hired'

Now back to our problem, after we implement Enums our code will look like this,

enum State {
applied = 1,
interview = 2,
hired = 3 ,
rejected = 4
}
var application = {
name: 'Sami Najar',
status: State.applied
}
function changeStatus (application, newState) {
application.status = State[newState]
}
changeStatus (application, 'interview')

Notice how we write the status code only once, the State Enum will return the right status code according to the given state.

Now the application object should look like this,

{name: "Sami Najar", status: 2}

and if we want to know the state of an application we will do this

function getState(application) {
return State[application.status]
}
getState(application) // return 'interview'

Well now at least we don’t need to care anymore about the states and their status, they are all managed by the State Enum, and even if we take a look at this code after a couple months, or someone else will work on it, this code is self explanatory!

If you are using a code editor that supports Typescript, it will show you an autocomplete of the values that the Enum supports. I think this help a lot!

And even if we try to get a property that doesn’t exist in the Enum, Typescript will notify us that it does not exit.

Computed Enums

By default Enums are auto incremented and they start with value zero, that means that this code

enum StatusCode {
info,
warn,
error,
log,
}

is the equivalent of this

enum StatusCode {
info = 0,
warn = 1,
error = 2,
log = 3,
}

If we want the Enum to start counting from other value other than zero, we can specify the starting value, we can change our previous State Enum to look like this, and it will be the same.

enum State {
applied = 1,
interview,
hired,
rejected
}

Enum property can rely on previous declared property like this,

enum Enum {
A = 1,
B = A + 2,
C = A + B
}

Now if we change property A’s value all other properties will be changed

Constant Enums

Back to the job application manager, On the left side Typescript code, and on the right side the generated Javascript

Typescript on left, Javascript on the right

Notice how Typescript converted State Enum into a State lookup object, and how the application status always gets its value from the State object.

But what if we don’t want the generated code to contain this State Object, or we don’t want to expose our status code and their meanings!

well we can, but it’s a bit tricky, check this code,

Typescript on left, Javascript on the right

Notice how Typescript removed the State look up object and replaced all strings literals with inlines values.

Well there’s no doubt that the generated code is now smaller and cleaner, but this will not fit our needs for some use cases.

Remember that previous changeStatus function. Let’s try to reuse it!

Typescript on left, Javascript on the right

Notice how Typescript notifies us that if we want to use const enum, we need to access it using a string literal.

In the generated Javascript code, we can see that the changeStatus function will still try to get values from the State object, and this will cause a run time error since Javascript can’t find the State Object.

Ambient Enums

The main reason to use Ambient Enums, is that we don’t want Typescript to generate the look up Object in Javascript, but rather than that a third party service (e.g: fetched from server) will offer it, let’s take this example,

Typescript on the left, Javascript on the right

Notice how we are getting the lookup State Object from a web server as JSON, then we use it as a replacement for State Enum,

Remember Typescript will not generate neither the lookup object of the Ambient Enum nor the Enum inline values. So make sure that you provide the lookup Object for your run time code!

Well this may not be the best use case but we tried to give an example of Ambient Enum uses. I don’t recommend it, and you might not need it.

One more thing you need to know, Enums properties accept only numbers.

That’s it for now, hope you understand Enums and their use cases. The next article of this series will be about Classes.

If you liked this, click the 💚 below so other people benefit

My Twitter: @mouafa

--

--

Mouafa Ahmed
codessert

Lead FrontEnd Developer, JavaScript Evangelist, UX Consultant, Instructor & Speaker