In TypeScript, Enums (short for Enumerations) are a way to define a set of named constants. They allow you to define a collection of related values in a more readable and structured way. Enums in TypeScript are particularly useful when you want to represent a fixed set of values, like the days of the week, status codes, colors, etc.
Types of Enums in TypeScript
TypeScript supports numeric enums, string enums, and heterogeneous enums. Let’s go through each type:
1. Numeric Enums
Numeric enums are the most basic and commonly used type of enum in TypeScript. By default, the values in a numeric enum start from 0
and increase by 1 for each member.
Example:
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
console.log(Direction.Up); // Output: 0
console.log(Direction.Left); // Output: 2
In this example, the Direction
enum has members Up
, Down
, Left
, and Right
, with values automatically assigned starting from 0
.
Setting Specific Values:
You can also manually assign values to some or all of the members of a numeric enum.
enum Status {
Pending = 1, // 1
InProgress, // 2
Completed, // 3
Archived // 4
}
console.log(Status.Pending); // Output: 1
console.log(Status.InProgress); // Output: 2
In this case, Pending
is assigned the value 1
, and the subsequent members (InProgress
, Completed
, Archived
) are automatically incremented from that point.
Reverse Mapping (from value to name):
TypeScript allows reverse mapping for numeric enums, meaning you can get the name of an enum member based on its numeric value.
enum Direction {
Up, // 0
Down, // 1
}
console.log(Direction[0]); // Output: 'Up'
2. String Enums
In string enums, each member must have a string value. This makes them more readable and useful when you need to send or store the values in a format that requires strings, such as API responses or configurations.
Example:
enum Color {
Red = "RED",
Green = "GREEN",
Blue = "BLUE"
}
console.log(Color.Red); // Output: "RED"
In this example, Color
is a string enum with the values "RED"
, "GREEN"
, and "BLUE"
. Each member is explicitly assigned a string value.
3. Heterogeneous Enums
Heterogeneous enums are a mix of numeric and string values. While this is generally not recommended for the sake of consistency, it is possible in TypeScript.
Example:
enum MixedEnum {
No = 0,
Yes = "YES"
}
console.log(MixedEnum.No); // Output: 0
console.log(MixedEnum.Yes); // Output: "YES"
Here, MixedEnum
contains both numeric and string values.
4. Computed and Constant Members
In TypeScript, enum members can either be constant or computed.
- Constant members are evaluated at compile-time (e.g., simple string or number assignments).
- Computed members are evaluated at runtime.
Example:
enum Constants {
A = 1,
B = A * 2, // Computed at runtime
C = 3
}
console.log(Constants.B); // Output: 2
In this example, B
is a computed value, since it depends on the value of A
at runtime.
5. Enums with Computed String Values
You can also use expressions to set string enum values, but they will be computed at runtime.
enum FileAccess {
Read = "READ",
Write = "WRITE",
Execute = "EXECUTE",
}
console.log(FileAccess.Read); // Output: "READ"
6. Enum as a Type
You can use the enum itself as a type. For example, if you define an enum, you can use it to ensure a variable or parameter can only take one of the enum values.
enum Role {
Admin = "ADMIN",
User = "USER",
}
let userRole: Role = Role.Admin; // Correct
userRole = Role.User; // Correct
// userRole = "Guest"; // Error: Type '"Guest"' is not assignable to type 'Role'
Enum Best Practices:
- Use string enums if you need clear, human-readable output or need to send the values in a specific format (e.g., to an API or a database).
- Use numeric enums when you need to map the enum values to numbers (e.g., for bitwise operations, or when interacting with existing systems that use numeric values).
- Avoid heterogeneous enums when possible, as they can lead to confusion and lack of consistency.
Summary of Features:
- Numeric Enums: Default type for enums where the values are numbers starting from 0 or specified manually.
- String Enums: Enum members are explicitly assigned string values.
- Heterogeneous Enums: Combination of both string and numeric values, though not generally recommended.
- Reverse Mapping: Numeric enums allow you to access enum names via their numeric values.
- Computed Members: Some enum members can be computed at runtime.
- Enum as Types: You can use the enum values as types to enforce that variables can only be one of the predefined values.
Example with All Features Combined:
enum UserRole {
Admin = "ADMIN",
User = "USER",
Guest = "GUEST",
SuperAdmin = "SUPER_ADMIN"
}
function getAccess(role: UserRole) {
if (role === UserRole.Admin) {
console.log("Access granted to Admin.");
} else if (role === UserRole.User) {
console.log("Access granted to User.");
} else {
console.log("Access denied.");
}
}
getAccess(UserRole.Admin); // Output: "Access granted to Admin."
In this example, UserRole
is a string enum that helps us ensure that only valid roles are passed to the getAccess
function, providing clear and maintainable code.