Understanding Enumerations

Post Editor

This article is an introduction to enumerated types or enum’s in both JavaScript and TypeScript. Unlike TypeScript, JavaScript doesn’t directly support enumerations. So we will look at a way to get some of the benefits of enumerated types in JavaScript.

5 min read
post

Understanding Enumerations

This article is an introduction to enumerated types or enum’s in both JavaScript and TypeScript. Unlike TypeScript, JavaScript doesn’t directly support enumerations. So we will look at a way to get some of the benefits of enumerated types in JavaScript.

post
post
5 min read

The Theory
Link to this section

In programming languages we typically use enumerations to describe finite sets of discrete values.

Discrete Values
Link to this section

When we talk about discrete values we mean values that are distinct and not continuous. There is a whole branch of mathematics called Discrete Mathematics that deals with these kinds of values.

From Wikipedia:

Discrete mathematics is the study of mathematical structures that are fundamentally discrete rather than continuous. In contrast to real numbers that have the property of varying “smoothly”, the objects studied in discrete mathematics — such as integers, graphs, and statements in logic— do not vary smoothly in this way, but have distinct, separated values.

For example:

  • Integers, booleans, and cardinal numbers are discrete.
  • Real numbers are continuous.

Another way to think about this is the idea that you can always find another value between continuous values. But, discrete values don’t have another value between them. For example, there is no integer between 1 and 2.

Cardinality
Link to this section

Cardinality is just a fancy way of saying the size of a set. For example, the cardinality of the set of the months of the year is 12.

Nothing in discrete mathematics says that the cardinality of a set must be finite. For example, there is an infinite number of items in the set of integers.

However, in programming our enumerations typically have a rather low cardinality.

Immutability
Link to this section

We say an object is immutable when it is not able to be changed. Sets of objects are often mutable. We can add new items to the set. Typically, we want our enumerations to be immutable so that they don’t get accidentally modified and cause bugs in our code.

JavaScript Enumerations
Link to this section

JavaScript does not have an enumerated type. However, you can easily create objects that act like enumerations:

<>Copy
const Color = { red: 0, blue: 1, yellow: 2, };

This works reasonably well as long as we are careful:

<>Copy
console.log ('We can use these like this:'); console.log ('Color.red:', Color.red); // Color.red: 0 console.log ('We get undefined when we use it incorrectly'); console.log ('Color.blew:', Color.blew); // Color.blew: undefined

Depending on our code, trying to use undefined would most likely result in a run-time error in our code. This would let us know that we had incorrectly used our enumeration.

Mutability
Link to this section

The problem is that our Color object is still mutable. Unfortunately, this means we can accidentally modify the Color object:

<>Copy
Color.yellow = 5; console.log ('Color.yellow:', Color.yellow); // Color.yellow: 5

To avoid this we can use the Object.freeze function. For example:

<>Copy
const Compass = { north: 0, east: 1, south: 2, west: 3 }; Object.freeze(Compass); console.log ('Compass.north:', Compass.north); // Compass.north: 0 // Now we try to modify the Compass object Compass.north = 5; console.log ('Compass.north:', Compass.north); // Compass.north: 0

You can also use the Object.isFrozen function to find out if an object has been frozen using Object.freeze. For example:

<>Copy
if (Object.isFrozen(Compass)){ console.log ('Compass is immutable.'); } else { console.log ('Compass is mutable.'); }

Integers Versus Strings
Link to this section

All of this assumes that we have some back-end system or function that requires an integer as the input. If you have the option, it is often useful to define your enumeration using strings.

<>Copy
const Compass = { north: 'north', east: 'east', south: 'south', west: 'west' }; Object.freeze(Compass);

This helps if you need to log the value or save it in a database. For example, now if we console.log our value we see:

<>Copy
console.log ('Compass.north:', Compass.north); // Compass.north: north

TypeScript
Link to this section

TypeScript directly supports enumerations using the enum keyword.

https://www.typescriptlang.org/docs/handbook/enums.html

In TypeScript we can define an enum like this:

<>Copy
enum Compass { North, East, South, West }

We can use them the same way we used our object in JavaScript:

<>Copy
let myDirection: Compass = Compass.North; console.log('myDirection', myDirection); // myDirection: 0

However, TypeScript has a build step. For example, let’s say we try to use an enum value that doesn’t exist:

<>Copy
// typo Sowth instead of South console.log('Compass.Sowth', Compass.Sowth);

In TypeScript we get a nice build-time error:

<>Copy
$ tsc tsenum.ts tsenum.ts:10:38 - error TS2551: Property 'Sowth' does not exist on type 'typeof Compass'. Did you mean 'South'? 10 console.log('Compass.Sowth', Compass.Sowth); ~~~~~ tsenum.ts:4:5 4 South, ~~~~~ 'South' is declared here. Found 1 error.

Notice, TypeScript is even smart enough to guess what we meant and make a recommendation.

Immutability

Also, TypeScript enum’s are immutable. For example, let’s say we try something like this:

<>Copy
// Try to add a new value to the enum Compass.SouthEast = 7; // Try to modify an existing value Compass.South = 7;

Of course, this gives us a build-time error as we would expect:

<>Copy
$ tsc tsenum-errors.ts tsenum-errors.ts:14:9 - error TS2339: Property 'SouthEast' does not exist on type 'typeof Compass'. 14 Compass.SouthEast = 7; ~~~~~~~~~ tsenum-errors.ts:15:9 - error TS2540: Cannot assign to 'South' because it is a read-only property. 15 Compass.South = 7; ~~~~~ Found 2 errors.

TypeScript enum Strings
Link to this section

By leveraging array notation we can even easily convert our enum to a string:

<>Copy
// We can even get the string value const directionName: string = Compass[Compass.South]; console.log('directionName', directionName); // directionName South

This works because our enum value directly matches the index of each item. It is even possible to use this trick for enum’s that are not zero based. For example, we can tell TypeScript to start numbering from 2 like this:

<>Copy
enum Compass { North = 2, East, South, West } // Yes, this still works const directionName: string = Compass[Compass.South]; console.log('directionName', directionName); // directionName South

Constant enums
Link to this section

As long as you are using constant values for your enum you really should make it a constant enum.

<>Copy
const enum Compass { North, East, South, West }

By adding that const in front of your enum, it will be completely removed during compilation. Const enum members are inlined at usage. This means any reference to the enum is replaced with the actual value in the resulting code.

For example, if I have the following TypeScript:

<>Copy
const foo: Compass = Compass.North;

After being compiled into JavaScript, it will look like this:

<>Copy
var foo = 0;

Hence, for the most part, constant enums give us all the benefits of enumerations with no overhead. Thanks to Russ Painter there is one exception that I need to mention: you won’t be able to use our little trick to convert to a string. For example, this will not work with a constant enum:

<>Copy
const directionName: string = Compass[Compass.South];

There’s More
Link to this section

This was just a quick introduction to enum’s. There’s lots more where that came from. TypeScript also supports String enums, Heterogeneous enums, Union enums, and Ambient enums.

To understand what these are, you can check out the TypeScript enum documentation here:
https://www.typescriptlang.org/docs/handbook/enums.html

Enumerated Types are used in many other programming languages. As we saw here they are worth understanding at a generic level:
https://en.wikipedia.org/wiki/Enumerated_type

If you want to know more about enumerations and how they relate to other types in Computer Science, you can read about Type Theory:
https://en.wikipedia.org/wiki/Type_theory

Share

About the author

author_image

Computer Scientist, Fujitsu Distinguished Engineer, and Senior Software Engineer http://t-palmer.github.io

author_image

About the author

Todd Palmer

Computer Scientist, Fujitsu Distinguished Engineer, and Senior Software Engineer http://t-palmer.github.io

About the author

author_image

Computer Scientist, Fujitsu Distinguished Engineer, and Senior Software Engineer http://t-palmer.github.io

Looking for a JS job?
Job logo
Senior Frontend Software Engineer (Angular)

Argument

Ukraine
Remote
$54k - $72k
Job logo
Front-End Web Software Engineer (Angular12 + ASP.NET)

MWS Technology

Ukraine
Remote
$36k - $60k
Job logo
Angular Software Developer

Salamander Technologies

America
Remote
$80k - $95k
Job logo
Senior Front End Developer - Angular

triValence

United States
Remote
$125k - $160k
More jobs

Featured articles