In TypeScript, enums (enumerations) are a powerful tool for defining sets of named constants. They enhance code readability, maintainability, and type safety by providing a clear structure for representing a collection of related values. This chapter delves into enums, exploring their creation, usage, and advanced features.
You can create an enum using the enum
keyword followed by a name and curly braces {}
containing the enum members:
enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
By default, enums are numeric. The first member starts at 0, and subsequent members are automatically assigned incremented values:
console.log(Weekday.Monday); // Output: 0
console.log(Weekday.Tuesday); // Output: 1
console.log(Weekday.Wednesday); // Output: 2
You can explicitly assign values to enum members:
enum Weekday {
Monday = 1,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
console.log(Weekday);
/* Output:
{
'1': 'Monday',
'2': 'Tuesday',
'3': 'Wednesday',
'4': 'Thursday',
'5': 'Friday',
'6': 'Saturday',
'7': 'Sunday',
Monday: 1,
Tuesday: 2,
Wednesday: 3,
Thursday: 4,
Friday: 5,
Saturday: 6,
Sunday: 7
}
*/
Now, Monday
has the value 1, and subsequent members continue automatic incrementation from there.
To assign specific values to all members, provide values for each:
enum HttpStatusCode {
OK = 200,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404
}
console.log(HttpStatusCode);
/* Output:
{
'200': 'OK',
'400': 'BadRequest',
'401': 'Unauthorized',
'404': 'NotFound',
OK: 200,
BadRequest: 400,
Unauthorized: 401,
NotFound: 404
}
*/
Enums can also contain string values:
enum FileType {
PDF = "pdf",
DOCX = "docx",
TXT = "txt"
}
Use the enum name followed by the dot (.
) and member name:
enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
const today = Weekday.Wednesday;
console.log(today); // Output: 2 (or "Wednesday" for string enums)
Enums provide optional reverse lookup to get the member name based on its value (not recommended for readability):
enum HttpStatusCode {
OK = 200,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404
}
const statusCode = 401;
const statusName = HttpStatusCode[statusCode]; // statusName will be "Unauthorized"
Enums ensure type safety by restricting variables to only allowed enum values:
enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
let day: Weekday;
day = Weekday.Thursday; // Valid
day = "Saturday"; // Error: Type '"Saturday"' is not assignable to type 'Weekday'
Enums are ideal for switch statements:
enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
function getWeekendGreeting(day: Weekday) {
switch (day) {
case Weekday.Saturday:
case Weekday.Sunday:
return "Enjoy your weekend!";
default:
return "Have a productive day!";
}
}
console.log(getWeekendGreeting(Weekday.Friday)); // Output: "Have a productive day!"
console.log(getWeekendGreeting(Weekday.Saturday)); // Output: "Enjoy your weekend!"
const
enums are optimized for compile-time usage, reducing runtime overhead:
const enum Color {
Red = "red",
Green = "green",
Blue = "blue"
}
However, they cannot be used for reverse lookup or with typeof
.
You can use expressions to define enum member values dynamically:
enum HttpStatus {
OK = 200,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
ServerError = 500 + Math.floor(Math.random() * 100) // Random value between 500 and 599
}
While enums are primarily for constants, you can add methods for basic operations within the enum definition. However, use this approach cautiously, as it can blur the lines between enums and classes:
enum File {
TXT,
PDF,
DOCX,
getExtension(this: File) {
switch (this) {
case File.TXT:
return ".txt";
case File.PDF:
return ".pdf";
case File.DOCX:
return ".docx";
}
}
}
console.log(File.TXT.getExtension()); // Output: ".txt"
Enums can be used as types within interfaces to enforce stricter type checking:
interface Product {
name: string;
price: number;
category: FileType; // Enum used as a type
}
const product: Product = {
name: "My Book",
price: 19.99,
category: FileType.PDF // Ensures category is a valid FileType
};
Enums can be used with generics to create flexible data structures:
function identify(value: T, type: { [key: string]: T }) {
return type[value as keyof typeof type]; // Enum used as keyof
}
const fileType = identify("txt", FileType); // fileType will be ".txt"
const statusCodeString = identify(404, HttpStatusCode); // statusCodeString will be "NotFound"
Combine mapped types with enums to create objects with properties based on enum values:
type WeekdayGreetings = {
[key in Weekday]: string;
};
const greetings: WeekdayGreetings = {
[Weekday.Monday]: "Hello, Monday!",
// ... greetings for other weekdays
};
console.log(greetings[Weekday.Tuesday]); // Output: (greeting for Tuesday)
Use enums with utility types like Partial<T>
or Pick<T, K>
to create subsets of enum values:
type WorkingDays = Partial; // WorkingDays allows any subset of Weekday values
type Weekend = Pick; // Weekend allows only Saturday and Sunday
const today: WorkingDays = Weekday.Wednesday; // Valid
const tomorrow: Weekend = Weekday.Sunday; // Valid
const
enums for compile-time optimization when appropriate.By effectively utilizing TypeScript enums and their advanced features, you can enhance code readability, maintainability, and type safety in your TypeScript projects. Remember to choose the right approach based on your specific requirements and maintain a balance between simplicity and advanced usage. Happy coding !❤️