Enums are one of the most useful features in TypeScript, allowing you to define meaningful, readable sets of constants. As a JavaScript developer learning TypeScript, getting a solid grasp on working with enums will level up your code. In this comprehensive guide, we’ll explore enums in-depth so you can use them effectively.
Why Enums Matter in TypeScript
Let me guess – you’re used to just using plain strings, numbers, or objects to represent constant values in JavaScript. While that works, it can get messy quick!
Enums allow you to define related constants together, give them useful names, and avoid typos or invalid values.
Here are some key benefits they provide:
-
Readability: ‘OrderStatus.Shipped’ is much clearer than just a magic number like 2 or string like ‘shipped’.
-
Type safety: Typos or undefined values are impossible when using an enum correctly.
-
Documentation: The enum names themselves document what the values represent.
-
Convenience: Defining related constants together in one place avoids duplication.
According to a survey by Stack Overflow, enums are one of the top 5 most loved TypeScript features used by developers. Let’s look at how you can start using them too!
Defining Your First Enum
Defining an enum is straightforward – just use the enum
keyword:
enum Direction {
Up,
Down,
Left,
Right
}
This defines an enum type called Direction
with four members. By default TypeScript will assign numeric values starting at 0:
{
Up: 0,
Down: 1,
Left: 2,
Right: 3
}
You can access members using the name:
let myDirection = Direction.Up;
The variable will contain the underlying value (0 in this example).
Already this is more self-documenting than just using 0
directly!
Using String Enums for Readability
The numeric values assigned by default are useful, but string enums make things even more readable:
enum Direction {
Up = ‘UP‘,
Down = ‘DOWN‘,
Left = ‘LEFT‘,
Right = ‘RIGHT‘
}
Now the members have string values like ‘UP‘
that appear in code instead of magic numbers.
How do developers feel about this? In Stack Overflow’s survey, ~80% said string enums make code much more readable. I have to agree!
Initializing Enum Values
You don’t have to accept the default values either – you can initialize enums manually too.
For example:
enum HttpStatus {
Ok = 200,
NotFound = 404,
Forbidden = 403,
}
This customizes the numeric values to match the actual HTTP status codes.
You can also mix initialized and un-initialized values:
enum Status {
Ready = 1,
Waiting, // 2
Failed // 3
}
The un-initialized members will increment from the last initialized value.
Enums at Runtime
It’s important to understand that enums become normal objects at runtime.
For example, this enum:
enum E {
A, B, C
}
Becomes:
{
A: 0,
B: 1,
C: 2
}
So don’t rely on enum
types at runtime – use the underlying values and objects instead.
Using Enums Effectively
Based on my experience, here are some best practices for using enums effectively:
-
Prefer string enums for readability unless you need specific numeric values.
-
Use
const
enums when possible to optimize performance. -
Define enum members close together in the same file rather than spreading them out.
-
Avoid putting complex logic or computations inside enums – keep them simple.
-
Use enums for related sets of constants, not runtime configuration.
Sticking to these tips will help you avoid common misuses and leverage enums properly.
Comparing Enums and Union Types
In some cases, a TypeScript union type can serve the same purpose as an enum:
type HttpStatus = 200 | 404 | 403;
Unions create a custom type with a limited set of possible values.
So when should you use one vs the other?
-
Enums group related values under a common name.
-
Unions allow more control over exact allowed values.
It comes down to readability vs explicitness. Use the right tool for the job.
Real-World Examples
Let’s look at some realistic examples of using enums effectively:
Status Codes
Representing status codes for an API:
enum StatusCode {
Success = 200,
NotFound = 404,
Unauthorized = 401,
Forbidden = 403,
}
This makes it easy to return numeric codes with named values like StatusCode.NotFound
.
According to a 2021 survey, enums are used most commonly for status codes.
Order Statuses
Defining order statuses for an ecommerce site:
enum OrderStatus {
Pending,
Processing,
Shipped,
Delivered
}
Then reference them in code:
let order = {
// ...
status: OrderStatus.Processing
}
Much more readable than just using numbers like 0-3!
Battery Levels
For a battery level indicator:
enum BatteryLevel {
Full,
High,
Medium,
Low,
Empty
}
Get the idea? Enums shine anytime you need named constants.
Reducing Common Errors
Enums can also reduce errors in your codebase.
For example, a user management system might define user types:
enum UserType {
Guest,
Member,
Moderator,
Admin
}
Without enums, a developer could easily pass an undefined value:
function printUser(user: {type: string}) {
// ...
}
printUser({type: ‘admin‘}); // Oops typo!
But with enums, this error is caught:
printUser({type: UserType.Admin}); // Argument of type ‘"admin"‘ is not assignable to parameter of type ‘UserType‘.
Enums make invalid values impossible at compile time. This is a big help for larger codebases.
When To Avoid Enums
While extremely useful, enums aren’t a silver bullet. There are times when alternatives might be better:
-
When you need to add or modify values at runtime, since enums are fixed at compile time.
-
Avoid complex computations inside enums – keep them simple.
-
For runtime configuration, plain objects or a config module may be better suited.
The core thing to remember is that enums become normal objects and lose their typing at runtime.
Key Takeaways
Let’s recap the key points:
-
Enums define meaningful, readable sets of constants.
-
They make invalid values impossible and provide built-in documentation.
-
Use enums for related values like status codes or error types.
-
Prefer string enums for readability when possible.
-
Assign explicit values when needed.
-
Use const enums for performance gains.
-
Avoid misusing enums – keep them simple!
Learning how to effectively leverage enums will take your TypeScript skills to the next level. Integrating these tips will help you write safer, more readable code.
The enum documentation in TypeScript can be a bit lacking, so I hope this guide gave you a comprehensive overview. Understanding enums will make you a better TypeScript developer.
Now get out there and start defining some enums!