This post will explain how to implement and use enumerations (or enum types) in Javascript.

banner image

Enums are types that contain a limited number of fixed values, as opposed to types like Number or String which can have a wide range of values.

This is useful for many situations: For example, when describing seasons in temperate climates, you’ll want to limit the options to certain possible values: Summer, Winter, Spring and Autumn.

enums contain only a limited set of values

Let’s look at different ways of implementing this type of data:

Defining Enums as Object Keys

For a basic implementation of enums, we can define an object to encapsulate the enum type, and assign a key for each enum value.

For example, we can represent seasons as on object with each season as the key, and a representative string as the value:

const Seasons = {
	Summer: "summer",
	Autumn: "autumn",
	Winter: "winter",
	Spring: "spring"
}

We can also do this by using numbers as values:

const Seasons = {
	Summer: 0,
	Autumn: 1,
	Winter: 2,
	Spring: 3
}

While this would work for small codebases, we will face a few immediate issues:

  1. It’s easy to make mistakes in your code. A developer can make the mistake of using integers outside the range of the ones defined, or make a spelling mistake when using strings.

    const Seasons = {
    	Summer: "summer",
    	Autumn: "autumn",
    	Winter: "winter",
    	Spring: "spring"
    }
    const mySeason = "summr"
    
    // this would be false because of the spelling mistake in `mySeason`
    console.log(mySeason === Seasons.Summer)
    

    ``

  2. Definitions from unrelated enums can overlap and cause conflicts:

     const Seasons = {
     	Summer: 0,
     	Autumn: 1,
     	Winter: 2,
     	Spring: 3
     }
    
     const Fruits = {
     	Apple: 1,
     	Orange: 1
     }
    
     // Ideally, this should never be true!
     console.log(Seasons.Summer === Fruits.Apple)
    
  3. Using primitives (like strings or numbers) as values is semantically incorrect - Seasons are not really integers or strings – they’re seasons and should have their own types for better semantic representation.

Enums with Symbols

Symbols let us define values that are guaranteed not to collide with one another.

For example:

const Summer1 = Symbol("summer")
const Summer2 = Symbol("summer")

// Even though they have the same apparent value
// Summer1 and Summer2 don't equate
console.log(Summer1 === Summer2)
// false

console.log(Summer1)

We can define our enums using Symbols to ensure that they are not duplicated:

const Seasons = {
	Summer: Symbol("summer"),
	Autumn: Symbol("autumn"),
	Winter: Symbol("winter"),
	Spring: Symbol("spring")
}

let season = Seasons.Spring

switch (season) {
	case Seasons.Summer:
	console.log('the season is summer')
	break;
	case Seasons.Winter:
	console.log('the season is winter')
	break;
	case Seasons.Spring:
	console.log('the season is spring')
	break;
	case Seasons.Autumn:
	console.log('the season is autumn')
	break;
	default:
		console.log('season not defined')
}

Using Symbols ensures that the only way we can assign an enum value is by using the values that we defined initially.

Please note that Symbols cannot be serialized into JSON, so if you plan on converting an object containing this enum into a JSON string, you should consider the previous method of using object keys instead

Making Enum Objects Immutable

In the previous examples, it’s possible to change the value of an enum by modifying the enum object. For example, we can change the Seasons object like so:

const Seasons = {
	Summer: Symbol("summer"),
	Autumn: Symbol("autumn"),
	Winter: Symbol("winter"),
	Spring: Symbol("spring")
}

Seasons.Winter = "winter" // this will overwrite the `Symbol` with a string 

For larger codebases, these kind of errors may be introduced unintentionally. We can use Object.freeze to prevent these kind of changes:

const Seasons = Object.freeze({
	Summer: Symbol("summer"),
	Autumn: Symbol("autumn"),
	Winter: Symbol("winter"),
	Spring: Symbol("spring")
})

Seasons.Winter = "winter" // this won't change the `Seasons` object because its been frozen

Enums with Classes

To make our code more semantically correct, we can create a class to hold groups of enums.

For example, our seasons should have a way for us to identify that they all belong to a similar classification.

Let’s see how we can use classes and objects to create distinct enum groups:

// Season enums can be grouped as static members of a class
class Season {
  // Create new instances of the same class as static attributes
  static Summer = new Season("summer")
  static Autumn = new Season("autumn")
  static Winter = new Season("winter")
  static Spring = new Season("spring")

  constructor(name) {
    this.name = name
  }
}

// Now we can access enums using namespaced assignments
// this makes it semantically clear that "Summer" is a "Season"
let season = Season.Summer

// We can verify whether a particular variable is a Season enum
console.log(season instanceof Season)
// true
console.log(Symbol('something') instanceof Season)
//false

// We can explicitly check the type based on each enums class
console.log(season.constructor.name)
// 'Season'

Listing All Possible Enum Values

If we used the class-based approach above, we can loop through the keys of the Season class to obtain all the enum values under the same group:

Object.keys(Season).forEach(season => console.log("season:", season))
// season: Summer
// season: Autumn
// season: Winter
// season: Spring

We can do the same with the object-based approach as well:

const Seasons = Object.freeze({
	Summer: Symbol("summer"),
	Autumn: Symbol("autumn"),
	Winter: Symbol("winter"),
	Spring: Symbol("spring")
})

Object.keys(Seasons).forEach(season => console.log("season:", season))
// season: Summer
// season: Autumn
// season: Winter
// season: Spring

When to Use Enums in Javascript?

In general, enums are helpful if there are a definite number of fixed values for any one variable.

For example, the crypto standard library for Node.js has a list of supported algorithms, that can be considered an enum group.

Using enums in Javascript correctly will lead to better code that is more stable, easier to read and less error prone.