How Does An Enum Work In TypeScript?
If you come from an object-oriented language like Java or C#, you may be surprised that JavaScript doesn't support the enum data type. Luckily, our favorite TypeScript supports it.
An enum allows the declaration of a set of related values. Here is an example in TypeScript:
typescriptenum HttpCodes {
Success = 200,
NotFound = 404
};
This article explains the enum data type and when to use it and shows many code examples.
Let's get to it 😎.
The definition
An enum or enumeration is a special data structure that allows the declaration of a set of related named values. In short, it represents a group of constants.
To declare an enum, use the enum keyword.
In TypeScript, enums can contain string or numerical values.
A developer can use an enum when wanting to limit a variable or function input to a small set of accepted answers. For example, let's say you have a function that can only accept a cardinal direction as the input. There are only four cardinal directions. An enum is perfect in that case.
typescriptenum CardinalDirection {
North,
West,
South,
East
}
In TypeScript, an enum can be of type:
- Default (numeric values)
- String
- Computed
- Heterogeneous
Unlike the interface, the TypeScript enum exists at runtime unless exported as a const.
Types of enums
1. Default enum
By default, a TypeScript enum is numeric AND doesn't require initialization.
Its first value starts at zero and adds 1 to each additional value.
Here is an example:
typescriptenum CardinalDirection {
North,
West,
South,
East
}
// Outputs: 0
console.log(CardinalDirection.North);
// Outputs: 1
console.log(CardinalDirection.West);
// Outputs: 2
console.log(CardinalDirection.South);
// Outputs: 3
console.log(CardinalDirection.East);
You can also initialize its first value so that it starts at another number than zero:
typescriptenum CardinalDirection {
North = 2,
West,
South,
East
}
// Outputs: 2
console.log(CardinalDirection.North);
// Outputs: 3
console.log(CardinalDirection.West);
// Outputs: 4
console.log(CardinalDirection.South);
// Outputs: 5
console.log(CardinalDirection.East);
As you can see, the other values are also adjusted.
You can also fully initialize all the values of the enum, like in this example:
typescriptenum HttpCodes {
Success = 200,
Forbidden = 403,
NotFound = 404
};
// Outputs: 200
console.log(HttpCodes.Success);
// Outputs: 403
console.log(HttpCodes.Forbidden);
// Outputs: 404
console.log(HttpCodes.NotFound);
2. String enum
In TypeScript, you can also create an enum with string values.
A string enum is easier to debug AND better for the readability of your program.
Here is an example:
typescriptenum Role {
Manager = 'MANAGER',
Admin = 'ADMIN',
};
// Outputs: 'MANAGER'
console.log(Role.Manager);
// Outputs: 'ADMIN'
console.log(Role.Admin);
3. Computed enum
A TypeScript enum can also contain computed values from function returns, arithmetic operations, or constants.
Here is an example:
typescriptconst getAdminCode = () => 22;
enum Role {
Manager = 1,
Admin = getAdminCode(),
Owner = Manager * 10
};
// Outputs: 1
console.log(Role.Manager);
// Outputs: 22
console.log(Role.Admin);
// Outputs: 10
console.log(Role.Owner);
4. Heterogeneous enum
Finally, you can combine both string and numeric values inside an enum.
Here is an example:
typescriptenum Role {
Manager = 1,
Admin = 'ADMIN'
};
// Outputs: 1
console.log(Role.Manager);
// Outputs: 'ADMIN'
console.log(Role.Admin);
Reverse mapping
TypeScript enums also support reverse mapping.
It means that you can both access:
- The value of a member
- The member name from its value
Here is an example:
typescriptenum CardinalDirection {
North,
West,
South,
East
}
// Outputs: 1
console.log(CardinalDirection.West);
// Outputs: 1
console.log(CardinalDirection['West']);
// Outputs: 'West'
console.log(CardinalDirection[1]);
As you can see, accessing CardinalDirection[1] returns West because of reverse mapping.
Alternatives to enums
Many developers don't like the way TypeScript implements enums.
Here are some of the reasons why:
- Enums increase the size of the payload.
- They are challenging to iterate over.
- They are useless at runtime.
An alternative to creating an enum involves creating a type from an array via const assertion.
Here is an example:
typescriptconst roles = ['MANAGER', 'ADMIN'] as const;
type Roles = typeof roles[number];
In this example, we created a readonly tuple that is easier to understand and iterate over.
Here are some other alternatives:
- String unions
- Object literals
- Static class
How to convert an enum to an array?
In TypeScript, to convert an enum to an array, you can use:
- The Object.keys function
- The Object.values function
Here is an example:
typescriptenum Direction {
Up,
Down,
Left,
Right
}
// Outputs: ["Up", "Down", "Left", "Right"]
console.log(
Object.values(Direction).filter((v) => isNaN(Number(v)))
);
Read more here: How To Transform An Enum Into An Array In TypeScript?
How to add an enum property to a class?
TypeScript supports enum class properties.
Here's how you can declare one:
typescriptenum CardinalDirection {
North,
West,
South,
East
}
class Person {
private direction: CardinalDirection;
public constructor(direction: CardinalDirection) {
this.direction = direction
}
}
As you can see, we declare a class called Person that contains an enum property called direction.
Note: You can also declare the enum property as a readonly class constant.
Final thoughts
As you can see, declaring and using enums is easy in TypeScript.
However, they come with problems in TypeScript, like increasing your payload size and being hard to iterate over.
That's why some developers prefer alternatives like a tuple or union type.
Here are some other TypeScript tutorials for you to enjoy: