Nwose Lotanna Web Developer and Writer

TypeScript enums vs. types: Enhancing code readability

9 min read 2741

TypeScript Enums Vs. Types: Enhancing Code Readability

Editor’s note: This guide to TypeScript enums vs. types was last updated by Oyinkansola Awosan on 16 June 2023 to reflect recent changes to TypeScript. This update also includes new sections on extracting the object type of enums and converting enums to arrays. To learn more about enums, check out our guide to extending enums in TypeScript.

TypeScript (as you probably already know) is an open source, strongly typed, object-oriented compiled language developed and maintained by the team at Microsoft. It is a superset of JavaScript with static typing options. It is designed to develop large and scalable applications that compile to JavaScript.

Writing readable code is important. TypeScript types and enums contribute to code readability by providing clear and expressive ways to describe and work with data in TypeScript. In this article, we will be exploring how both work, why, and how to use them.

Jump ahead:

What are enums and types?

In most object-oriented programming languages like C, C#, and Java, there is a data type we know as enumerations — enums for short. Java enums are a special kind of Java class used to define collections of constants. JavaScript, however, does not have the enum data type, but they‘ve been available in TypeScript since v2.4.

Enums allow us to define or declare a collection of related values that can be numbers or strings as a set of named constants. Unlike some types available in TypeScript, enums are preprocessed and not tested at compile time or runtime. Enums are defined with the enum keyword, like this:

enum Continents {

// usage
var region = Continents.Africa;

In TypeScript, the type system refers to the various types of values the language accepts. A type refers to a value’s properties and functions; this means that every value in TypeScript has a type. The type system validates the values given before the program stores them.

The TypeScript compiler uses types to analyze your code and hunts for errors and bugs. Types are definitions of data types. This means a type of data is defined by its type. There are different types in TypeScript. Some common ones include:

  • Primitive types
  • Union types
  • Tuples
  • Arrays
  • Advanced types

Why use enums?

Enums are just one useful way to organize code in TypeScript. With enums, you can create constants that you can easily relate to, making constants more legible. Enums also allow developers the freedom to create memory-efficient custom constants in JavaScript. As we know, JavaScript does not support enums, but TypeScript helps us access them.

As mentioned, TypeScript enums save runtime and compile time with inline code in JavaScript (which we will see later in this article). And lastly, TypeScript enums also provide a certain flexibility that we previously had only in languages like Java. This flexibility makes it easy to express and document our intentions and use cases easily.

When to use enums

You should use enum types whenever you need to represent a fixed set of constants. That includes enum types such as the planets in our solar system and data sets where you know all possible values at compile time — for example, the choices on a menu, command line flags, etc.

This means that enums should ideally be used in situations where there are distinct values that can be seen as constants, like seven days of the week and the other examples given above:

enum Days {
  Sunday = 1,

Enums can be used inside array initializations just as other TypeScript data types. Here’s a quick example:

enum NigerianLanguage {

//can be used in array initialisation 
let citizen = {
  Name: 'Ugwunna',
  Age: 75,
  Language: NigerianLanguage.Igbo

Enums can also be used where strings or constants need to be represented in a variable.

When to avoid enums

TypeScript enums can be great to use, but there are scenarios where they are unnecessary. However, some developers tend to overlook these scenarios and go ahead to use them, which is not a great practice. Enums are best suited for representing a fixed set of values.

If you intend to reassign or change the enum member values, it is important to remember that enums are type-safe and, therefore, would return compile errors on reassignment. If you anticipate that the values will need to be dynamically generated at runtime, use constants or other data structures that may be more appropriate.

Enum values are usually defined upfront, and defining and managing a long list of constants within an enum can become cumbersome. As a result of this, enums should be avoided when working with large or open-ended sets of values. Using an enum may not be the best choice if the values to be represented are from an external data source.

Enums are primarily designed for compile-time constants and may not easily synchronize with external data sources. It is important to remember that the general idea behind enums was to help create a user-defined constants system.

Types of TypeScript enums

TypeScript enums are a way to define a set of named constants. They allow you to create a collection of related values that can be assigned to variables or used as a type. Enums provide a convenient way to work with a fixed set of values in a type-safe manner. By default, enums will initialize the first value to 0 and add 1 to each additional value. There are three types of TypeScript enums, namely:

  • Numeric enums
  • String enums
  • Heterogeneous enums

Numeric enums

By default, TypeScript enums are number-based. This means they can store string values as numbers. Numbers, and any other type that is compatible with them, can be assigned to an instance of the enum. Let’s say we want to store the days of the weekend. The representing enum in TypeScript can look something like this:

enum Weekend {

In the code block above, we have an enum we call Weekend. The enum has three values: Friday, Saturday, and Sunday. In TypeScript, like in other languages, enum values start from zero and increase by one for each member. They will be stored like this:

Friday = 0
Saturday = 1
Sunday = 2

We see that enums are always assigned numbers for storage; the value always takes the numeric value of zero, although we can customize the storage values with our own logic.

Custom numeric enums

In TypeScript, we can dictate the first numeric value of our enumerations. Using the weekend days example above, we can initialize the first numeric value like this:

enum Weekend {
  Friday = 1,

The above code block will store Friday as 1, Saturday as 2, and Sunday as 3. If we add a number to the first member, we still get sequential incrementation by one for the rest of the members. However, we have the power to dictate that we do not want a sequential trail by giving them any numerical value. The code block below is semantic and works in TypeScript:

enum Weekend {
  Friday = 1,
  Saturday = 13,
  Sunday = 5

Just like other data types in TypeScript, we can use enums as function parameters or return types, like this:

enum Weekend {
  Friday = 1,
function getDate(Day: string): Weekend {
    if ( Day === 'TGIF') {
        return Weekend.Friday;
let DayType: Weekend = getDate('TGIF');

We declared a Weekend enum above. We then declared a getDate function that takes the input Day, which returns a Weekend enum. In the function, we check for some condition that now returns an enum member.

Computed enums

The value of a numeric enum can either be constant or evaluated, just like any other number data type in TypeScript. You can define or initialize your numeric enum with a computed value:

enum Weekend {
  Friday = 1,
  Saturday = getDate('TGIF'),
  Sunday = Saturday * 40

function getDate(day : string): number {
    if (day === 'TGIF') {
        return 3;
Weekend.Saturday; // returns 3
Weekend.Sunday; // returns 120

When enums include a mixture of computed and constant members, the enum members that are not initialized either come first or must come after other initialized members with numeric constants. Ignoring this rule above results in an initializer error; remember to rearrange the enum members accordingly if you see that.

Const enums

If you want to boost the performance of your numeric enums, you can declare them as a constant. Let’s use our weekend example to illustrate:

enum Weekend {
  Friday = 1,
var day = Weekend.Saturday;

When compiled to JavaScript, the runtime looks up Weekend and looks up Weekend.Saturday at execution. For optimal performance at runtime, you can make the enum a constant instead, like this:

const enum Weekend {
  Friday = 1,
var day = Weekend.Saturday;

The JavaScript generated at compile with the constant is:

var day = 2;

We see how the compiler just inlines the enum usages and does not even bother generating JavaScript for enum declarations when it sees the const. It is important to be aware of this choice and the consequences that may result when you have use cases that require number-to-strings or strings-to-number lookups. You can also pass the compiler flag preserveConstEnums, and it will still generate the Weekend definition.

String enums

So far, we have only looked at numeric enums, wherein the member values are numbers. In TypeScript, your enum members can also be string values. String enums are vital and easy to deal with for the purpose of readability during error logging and debugging because of their meaningful string values. Refer to the following code:

enum Weekend {
  Friday = 'FRIDAY',
  Saturday = 'SATURDAY',
  Sunday = 'SUNDAY'

It can then be used to compare strings in conditional statements like this:

enum Weekend {
  Friday = 'FRIDAY',
  Saturday = 'SATURDAY',
  Sunday ='SUNDAY'
const value = someString as Weekend;
if (value === Weekend.Friday || value === Weekend.Sunday){
    console.log('You choose a weekend');

In the example above, we have defined a string enum, Weekend, just like the numeric enum we had above, but this time with the enum values as strings. The obvious difference between numeric and string enums is that numeric enum values are mostly sequentially incremented automatically, while string enum values are not incremented; rather, each value is initialized independently.

Heterogeneous enums

TypeScript also allows for a mixture of strings and numbers, called heterogeneous enum. In this type of enum, we can assign numeric and string values to its members. This type of enum is used sparingly as it has few applications and is more limited. Refer to this example:

enum Weekend {
  Friday = 'FRIDAY',
  Saturday = 1,
  Sunday = 2

Although this is possible, the range of scenarios that will likely require this use case is small. So, unless we are trying to take advantage of JavaScript’s runtime behavior in a clever way, it is advised that we do not use heterogenous enums.

Using enums for reverse mapping

TypeScript enums support reverse mapping, which simply means that just as we have access to the value of an enum member, we also have access to the enum name itself. We’ll use a sample of our first demonstration to portray this:

enum Weekend {
  Friday = 1,

In the code block above, Weekend.Saturday will return 2, and then Weekend["Saturday"] will also return 2. Interestingly, however, due to reverse mapping, Weekend[2] will return its member name Saturday. We can see a simple way TypeScript interprets reverse mapping with a log command:

enum Weekend {
  Friday = 1,

If you run this in a console, you will see this output:

  '1': 'Friday',
  '2': 'Saturday',
  '3': 'Sunday',
  Friday   : 1,
  Saturday : 2,
  Sunday  : 3

The objects contain the enums appearing both as values and as names, just as TypeScript intended. This shows the potency of reverse mapping in TypeScript.

Extracting object types of enums

To extract the object types of enums in TypeScript, you can use the keyofoperator in combination with the enum itself. Here’s an example:

enum Color {
  Red = 'RED',
  Green = 'GREEN',
  Blue = 'BLUE',

type ColorKey = keyof typeof Color; // 'Red' | 'Green' | 'Blue'
type ColorValue = typeof Color[ColorKey]; // 'RED' | 'GREEN' | 'BLUE'

const colorKey: ColorKey = 'Red';
const colorValue: ColorValue = Color[colorKey];

console.log(colorKey); // Output: 'Red'
console.log(colorValue); // Output: 'RED'

In this example, the keyof typeof Color expression extracts the keys of the Color enum: Red, Green, and Blue. The resulting type is ColorKey, a union type of the keys Red, Green, and Blue.
The typeof Color[ColorKey] expression accesses the values of the Color enum using the extracted keys. This results in the type ColorValue, a union type of RED, GREEN, and BLUE.

You can then use the ColorKey type to declare variables that can hold enum keys and the ColorValue type to declare variables that can hold enum values. In the example, colorKey is assigned the value Red, which is a valid key of the Color enum. Similarly, colorValue is assigned the corresponding value of RED. The outputs of console.log(colorKey) and console.log(colorValue) are Red and RED, respectively.

How to convert an enum to an array

To transform a numeric enum into an array, there are two options available in TypeScript:

  • Object.values function
  • Object.keys function

Using the Object.values function would look like what we have below:

enum Colors {
console.log(Object.values(Color).filter((v) => isNaN(Number(v)))

TypeScript enums best practices

There are certain use cases where it’s optimal and efficient to use enums. There are also instances when you should put the enums away. Below, we’ll discuss TypeScript enums best practices. When working with a language and its concepts, following the best practices to ensure clean and maintainable code is essential. For TypeScript enums, here are some recommended best practices:

  • Capitalize enum names: When naming enums, one should follow the convention of using uppercase letters. For example, enum Animal is preferred over enum animal
  • Use string enums: If possible, use string enums instead of numeric enums. String enums are more readable, making the code easier to understand as they are more descriptive. They also help to avoid issues when members are modified or reordered. For numeric-based values or bitwise operations, use numeric enums
  • Assign values explicitly: When defining them, it is essential to assign values to enums explicitly. This helps to avoid unexpected behaviors and maintain consistency across different environments
  • Avoid automatic enum value assignment: TypeScript automatically assigns numeric values to enum members if not explicitly assigned. It is recommended to deactivate this by specifying a value for each enum. This prevents unintended changes to the enum when modifying or reordering its members

By following these best practices, you can ensure that your TypeScript enums are well-defined and maintainable and enhance the overall readability of your code.

TypeScript enums vs. alternatives

Depending on your use case, there are some alternatives to TypeScript enums that you can use. Some of them include the union of string literals types and the as const. A union of string literals is a type that represents a specific set of string values. It allows you to define a type that can only accept one of the specified string literals, providing a more restrictive and specific type constraint.

Using a union of string literals, TypeScript performs static type checking and ensures that only the specified string literals are allowed for variables of the declared type. This improves type safety and eliminates potential runtime errors caused by assigning invalid values.

The as const assertion is applicable when you want to ensure that values or expressions are treated as immutable and their types are narrowed down to their literal representations. This can provide additional type safety and enable TypeScript to perform more accurate type inference. as const lets you generate your types from your data.


We have been able to take a good look at enums in TypeScript, including their types and properties. We also saw the syntax and practical examples of how they are used. We saw other important enums aspects like constants in enums, computed enums, and even reverse mapping.
It is noteworthy that for string enums, reverse mapping is not supported. Also, for the heterogeneous ones, it is only supported for numeric type members but not for string type members. Happy coding!

Further reading:

: Full visibility into your web and mobile apps

LogRocket Dashboard Free Trial Banner

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

Try it for free.
Nwose Lotanna Web Developer and Writer

One Reply to “TypeScript enums vs. types: Enhancing code readability”

Leave a Reply