Improving your JavaScript with Enums
Tags: javascript, programming, webdev, algorithms
Published: 2022-08-28 04:06:52

Enumerations (Enums) are a common data structure feature in many programming languages. While JavaScript does not natively have this feature, we can quickly and easily add them.

## What is an Enum?

Before we jump into the code and learn how to create an Enum, we should discuss what one is. Let's start with an Array. This Array is a list of possible error types that we could have in our web app.

```js
const errors = ['Data Error', 'Lunch Error', 'Mom Error'];
```

While an Array allows us to store a list of error types that could be used later, it does require the developer to memorized the names and the order that they appear in the Array. 

```js
console.log( errors[0] );
//if you remember that zero refers to 'DataError'
//then you get the right value.
```

An Enumeration solves this problem by creating an **uneditable** list of values where each value has a String name as the key.

So, this can be more closely replicated with a JavaScript Object.

```js
const errors = {
  DATAERROR: 'Data Error',
  LUNCHERROR: 'Lunch Error',
  MOMERROR: 'Mom Error'
}
```

With an Object we avoid this issue of having to remember the position of each value.

```js
console.log( errors['DATAERROR'] );
```

We still have the problem that any of the keys or values can be edited or removed.

So, an Enumeration is a list of key-value pairs that cannot be altered at runtime.

## Creating JavaScript Enums

Accepting that an Object is a better choice than an Array for replicating an Enum, we need to solve the readonly issue. That brings us to the `Object.freeze` method.

The `Object.freeze` method that allows us take any object and change the configurable and writable property descriptors of every property so that no changes can be made to either the key or the value. 

```js
const errors = Object.freeze({
  DATAERROR: 'Data Error',
  LUNCHERROR: 'Lunch Error',
  MOMERROR: 'Mom Error'
});

console.log( errors['LUNCHERROR'] );
//we can use either square bracket syntax 
//or dot notation to access the values
console.log( errors.MOMERROR );
```

The use of `const` will also prevent any new value being assigned to `errors` and replacing the original Object.

## Applications of Enums

As an example for how we could use our Enum we can imagine a simple web app that attempts to do some asynchronous tasks, in sequence, and when it fails any of them, it will throw an error that is specific to the task.

```js
Promise.resolve(123)
  .then(async (id)=>{
    let url = `https://example.com/users/${id}`;
    let resp = await fetch(url)
    if(!resp.ok) throw new Error(errors['DATAERROR']);
    return 'burger';
  })
  .then(async (food) => {
    let isGood = await enjoyAsyncLunch(food);
    if(!isGood) throw new Error(errors['LUNCHERROR']);
    return true;
  })
  .then((ready) => {
    if( !askMomForPermission() ) throw new Error(errors.MOMERROR);
  })
  .catch((err)=> {
    console.error(`Reason for failure is ${err.message}`);
  });
```

A nice added benefit of creating our Enum Object is that now, most IDEs, like VSCode, will be able to use code-complete to show you the possible values for errors.