Introduction
An enumeration, or enum, is a feature in TypeScript that allows us to define a set of named constants. Using enums can make it easier to document intent or create a set of distinct cases. This guide will walk you through the versatility of enums in TypeScript with practical code examples.
Understanding Enums
In TypeScript, an enum is a way of giving more friendly names to sets of numeric values. Define an enum using the enum
keyword:
enum Direction {
Up,
Down,
Left,
Right
}
By default, enums begin numbering their members starting at 0. You can access the values using the dot notation:
let go: Direction = Direction.Up;
Enums can be assigned numbers directly, providing a custom numeric value for each member.
enum Status {
NotStarted = 1,
InProgress,
Completed
}
console.log(Status.InProgress); // Outputs 2
String Enums
In TypeScript, enums can also be strings. Here’s how you define enums with string values:
enum PrintMedia {
Newspaper = 'NEWSPAPER',
Newsletter = 'NEWSLETTER',
Magazine = 'MAGAZINE',
Book = 'BOOK'
}
String enums offer the benefit of runtime introspection and more readable values.
Heterogeneous Enums
Enums can also contain both string and number values. These heterogeneous enums are not as commonly used but are legal in TypeScript:
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = 'YES',
}
Computed and Constant Members
Enum members can be constant (the default) or computed. A constant member can take certain forms.
enum FileAccess {
// Constant members
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
// Computed member
GigaByte = 1 << 30
}
Here, ReadWrite
is computed from the constant members Read
and Write
, and GigaByte
is a computed value.
Union Enums and Enum Member Types
Sometimes you want to use enums as a union of each enum member. TypeScript allows enums to be used as types:
enum ShapeKind {
Circle,
Square,
}
interface Circle {
kind: ShapeKind.Circle;
radius: number;
}
interface Square {
kind: ShapeKind.Square;
sideLength: number;
}
Now, Circle.kind
can only ever be ShapeKind.Circle
.
Enums at Runtime
Enums are real objects that exist at runtime. For example, you can pass around enums and values from them like any other object:
enum LogLevel {
ERROR, WARN, INFO, DEBUG
}
/**
* This is equivalent to Object.keys(LogLevel).map(k => LogLevel[k]).
* It returns the string names of each enum member.
*/
function printImportant(key: string, message: string) {
const num = LogLevel[key];
if (num <= LogLevel.WARN) {
console.log('Log level key is:', key);
console.log('Log level value is:', num);
console.log('Log level message is:', message);
}
}
printImportant('ERROR', 'This is a message');
Enums at Compile Time
TypeScript enums are removed during the compilation to JavaScript. However, reverse mappings are created by TypeScript as well:
enum Tristate {
False,
True,
Unknown
}
let myState = Tristate[Tristate.True];
console.log(myState); // Outputs 'True'
Const Enums
Const enums are a TypeScript specific construct that can offer better performance compared to regular enums:
const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
// In generated code will become
// let directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
Working with Flagged Enums
Sometimes you might want enums to support combinations of values, known as bit flags:
enum FileAccess {
None,
Read = 1 << 0,
Write = 1 << 1,
ReadWrite = Read | Write,
GigaByte = 1 << 2
}
let fileAccess = FileAccess.ReadWrite | FileAccess.GigaByte;
console.log(fileAccess); // Outputs 7
Best Practices for Using Enums
Consider using enums for better code clarity when handling a predefined set of values. Always name enums and their members in a meaningful way, and use const enums when optimizing for performance.
Conclusion
TypeScript enums add structure to your code by allowing you to define a set of well-named constants. They are an essential feature for developers requiring type safety, expressiveness, and readability in their codebases. Grasp these concepts and patterns, and enums will no doubt become a valuable tool in your TypeScript arsenal.