enum HttpStatus {
Ok = 200,
Created = 201,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
ServerError = 500,
}
function isSuccessful(status: HttpStatus): boolean {
return status >= 200 && status < 300;
}
console.log(isSuccessful(HttpStatus.Ok)); // true
console.log(HttpStatus.NotFound); // 404
output
// true
// 404
Note Numeric enums auto-increment from the last explicit value. If no values are assigned, they start at 0. Beware: TypeScript allows assigning ANY number to a numeric enum variable, not just declared members — this is a known type safety gap.
numeric enumenum with numbersauto increment enumHTTP status enum
String Enums
syntax
enum Name {
Member = "value",
}
example
enum LogLevel {
Debug = "DEBUG",
Info = "INFO",
Warn = "WARN",
Error = "ERROR",
Fatal = "FATAL",
}
function log(level: LogLevel, message: string) {
console.log(`[${level}] ${message}`);
}
log(LogLevel.Error, "Database connection lost");
// log("ERROR", "..."); // Error: '"ERROR"' is not assignable to 'LogLevel'
output
// [ERROR] Database connection lost
Note String enums do NOT auto-increment — every member needs an explicit string value. They are more type-safe than numeric enums because you cannot accidentally pass an arbitrary string. The downside: you cannot pass the raw string value, only the enum member.
string enumenum with stringsnamed constantsenum values
const Enums
syntax
constenum Name {
Member = value,
}
example
constenum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
const playerDirection = Direction.Up;
// Compiles to: const playerDirection = "UP";// No Direction object exists at runtime
output
// const enums are completely erased — values are inlined at compile time
Note const enums produce zero runtime JavaScript — member accesses are replaced with literal values. However, they have compatibility issues: they cannot be used with --isolatedModules (Babel, esbuild, SWC), and they do not work across declaration files in some setups. Many teams ban them in favor of plain unions.
enum Permission {
Read = "READ",
Write = "WRITE",
Admin = "ADMIN",
}
// Each member is its own typefunction grantAdmin(userId: string, level: Permission.Admin) {
console.log(`Granting admin to ${userId}`);
}
grantAdmin("usr_1", Permission.Admin); // OK// grantAdmin("usr_1", Permission.Read); // Error: not assignable to Permission.Admin
output
// Individual enum members can be used as specific types
Note Each enum member is a subtype of the enum. You can use individual members in type positions to restrict parameters to a specific enum value. This is more useful with string enums since numeric enum members have the wider number type.
enum member typespecific enum valueenum subtypenarrow enum
Reverse Mapping (Numeric Enums)
syntax
EnumName[numericValue] // returns the member name as string
Note Reverse mapping ONLY works with numeric enums — string enums do not generate reverse mappings. The compiled JavaScript includes both name→value and value→name entries in the enum object. const enums do not support reverse mapping since they have no runtime object.
reverse mappingenum name from valuenumeric enum lookupenum to string
Union Types as Enum Alternatives
syntax
type Name = "value1" | "value2" | "value3";
example
// Instead of enum:type Theme = "light" | "dark" | "system";
// Object const pattern for when you need both runtime values and typesconst THEMES = {
Light: "light",
Dark: "dark",
System: "system",
} asconst;
type Theme2 = (typeof THEMES)[keyof typeof THEMES];
// "light" | "dark" | "system"function applyTheme(theme: Theme2) {
document.body.dataset.theme = theme;
}
output
// Union types achieve the same result without enum's quirks
Note Many TypeScript teams prefer string literal unions over enums for simplicity, full tree-shaking, and compatibility with --isolatedModules. The 'as const' object pattern gives you both runtime values (for iteration/lookup) and a derived type — the best of both worlds.