VOOZH about

URL: https://blog.logrocket.com/typescript-enums-vs-types/

⇱ TypeScript enums vs. types: Enhancing code readability - LogRocket Blog


2024-11-12
3160
#typescript
Nwose Lotanna
360
👁 Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

Editor’s note: This article was last updated by Oyinkansola Awosan on 12 November 2024 to cover converting strings to enums and to compare TypeScript enums and constants.

👁 TypeScript Enums Vs. Types: Enhancing Code Readability

TypeScript enums are a special feature that allows you to define a collection of constant values. They typically make code more readable and are particularly useful for representing a fixed set of values, such as directions, status codes, or user roles. They provide a way to give more descriptive names to sets of related values, making your code more intuitive.

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 so:

enum Continents {
 North_America,
 South_America,
 Africa,
 Asia,
 Europe,
 Antartica,
 Australia
}

// usage
var region = Continents.Africa;

🚀 Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

What are TypeScript types?

In TypeScript, the type system refers to the various types of values the language accepts. Type defines the structure of data; it also 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. They allow you to specify the expected data types for variables, function parameters, and return values. This strict typing helps catch potential errors early in the development process and improves code quality. Unlike enums, types focus on defining what data should look like rather than assigning specific values.

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,
 Monday,
 Tuesday,
 Wednesday,
 Thursday,
 Friday,
 Saturday
}

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

enum NigerianLanguage {
 Igbo,
 Hause, 
 Yoruba
}

//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 use them anyway, 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’s 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 zero and add one 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 {
 Friday,
 Saturday,
 Sunday
}

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.


Over 200k developers use LogRocket to create better digital experiences

👁 Image
Learn more →

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,
 Saturday,
 Sunday
}

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,
 Saturday,
 Sunday
}
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 and 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 this:

enum Weekend {
 Friday = 1,
 Saturday,
 Sunday
}
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,
 Saturday,
 Sunday
}
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 doesn’t even bother generating JavaScript for enum declarations when it sees the const. It’s 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');
 console.log(value); 
}

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’s advised that we don’t use heterogeneous 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,
 Saturday,
 Sunday
}
Weekend.Saturday 
Weekend["Saturday"]; 
Weekend[2];

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,
 Saturday,
 Sunday
}
console.log(Weekend);

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 keyof operator 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 strings to enums

There is no explicitly direct way to convert strings to enums as such converting a string to an enum is not straightforward. However, there are multiple ways to convert a string to an enum and we will be exploring two effective methods:

Lookup object

This method involves using a lookup object to create a mapping between strings and their corresponding enum members, allowing for easy and efficient conversion from strings:

enum Children {
 First = "Tirenii",
 Second = "Anita",
 Third = "Oluwaseun",
}

const enumLookup: { [key: string]: Children } = {
 First: Children.First,
 Second: Children.Second,
 Third: Children.Third,
};

function convertStringToEnum(value: string): Children | undefined {
 return enumLookup[value];
}

console.log(convertStringToEnum("First")); 
console.log(convertStringToEnum("Second")); 

In the code above, we define an enum Children with string values representing child names. The convertStringToEnum function uses a lookup object, enumLookup, to map a string input e.g., First to the corresponding Children enum value like Children.First. The function returns the associated enum value or undefined if the string is not found in the lookup object.

Reverse mapping

Reverse mapping, which we covered earlier, is an effective way of converting strings to enums as it maps enum values back to their corresponding keys:

enum Cars {
 Honda = 9,
 Toyota = 6,
 Kia = 4,
}

function stringToEnum(value: string): Cars | undefined {
 const key = Object.keys(Cars).find((key) => key === value);
 if (key) {
 return Cars[key as keyof typeof Cars];
 }
 return undefined;
}

console.log(stringToEnum("Honda"));
console.log(stringToEnum("Toyota"));
console.log(stringToEnum("Kia"));

In the code above, we define an enum Cars with numeric values assigned to the car brands. The stringToEnum function uses reverse mapping to convert a string representation of a car brand to its enum value. It iterates through the keys of the Cars enum, finds the matching key based on the input string and then returns the associated enum value.

If no match is found, it returns undefined. If one is found, it returns the assigned value.

How to convert an enum to an array

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

  • The Object.values function
  • The Object.keys function

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

num Colors {
 Red,
 Blue,
 Yellow
}
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, the enum Animal is preferred over the 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:

  • Using a union of string literals: 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
  • Using the as const assertion: 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

TypeScript enums vs. constants

Constants in TypeScript are variables with unchangeable values that are generally used within an object or array using const declarations. They enhance code readability and are declared by using const.

Choosing between enums and constants depends largely on your specific needs. Enums are ideal when you require a structured grouping of related values, especially when their meaning is crucial to the application. On the other hand, constants are better suited for lightweight and flexible use cases where runtime efficiency is a priority:

TypeScript enums Constants
Runtime behavior Transpiles into a JavaScript object, which adds some runtime overhead due to object lookups Directly translates to JavaScript, with no added runtime behavior hence it is faster with no object lookups
Flexibility Limited flexibility compared to constants because they are rigid once defined Highly flexible and can be assigned any data type, providing more flexibility in defining values
Use cases When structure is important, TypeScript enums are ideal because they represent a fixed set of related values and ensure type safety. Group related values semantically under a single name When runtime efficiency, immutability, and compatibility with JavaScript features are priorities. Lightweight representation of fixed values. Constants are also the best when there is a need for reusable and configuration values

Conclusion

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:

LogRocket understands everything users do in your web and mobile apps.

👁 LogRocket Dashboard Free Trial Banner

LogRocket lets you replay user sessions, eliminating guesswork by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings — compatible with all frameworks, and with plugins to log additional context from Redux, Vuex, and @ngrx/store.

With Galileo AI, you can instantly identify and explain user struggles with automated monitoring of your entire product experience.

Modernize how you understand your web and mobile apps — start monitoring for free.

👁 Image
👁 Image
👁 Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

Penguins and pasta: What I learned from making an app in 4 weeks with AI

I had four weeks to build a complete app from scratch using AI tools like OpenCode and Claude Opus: here’s how it went.

👁 Image
Lewis Cianci
Jun 2, 2026 ⋅ 10 min read

Build a headless table engine in Vue 3

Learn how to build a reusable Vue 3 table engine that powers tables, cards, and lists with shared sorting and pagination logic.

👁 Image
Carlos Mucuho
Jun 1, 2026 ⋅ 16 min read

Best React chart libraries in 2026: Features, performance, and use cases

Compare the best React chart libraries for 2026, including Recharts, Nivo, visx, Apache ECharts, MUI X Charts, and more.

👁 Image
Hafsah Emekoma
Jun 1, 2026 ⋅ 15 min read

I benchmarked Claude Code and OpenCode on a heavy refactor: The reality of agentic CLI workflows

Claude Code vs. OpenCode in a real Next.js refactor: benchmark results, mistakes, prompts, and when to use each CLI agent.

👁 Image
Chizaram Ken
May 28, 2026 ⋅ 11 min read
View all posts

Would you be interested in joining LogRocket's developer community?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now