Understand the limits of enums and derive your types from frozen constants with as const.
Open this lesson in Kodokonenum has been part of the language since its early days, and you'll run into it in plenty of codebases. It groups named constants under a single type, usable both as a value and as an annotation.
enum Role {
User = "USER",
Admin = "ADMIN",
}
function canDelete(role: Role): boolean {
return role === Role.Admin;
}Yet the modern ecosystem is moving away from it. An enum is syntax that doesn't exist in JavaScript: the compiler emits an object at runtime, which complicates certain tools and is incompatible with the erasableSyntaxOnly option. The alternative: a plain object frozen with as const, from which you derive the type.
const ROLES = {
User: "USER",
Admin: "ADMIN",
} as const;
type Role = (typeof ROLES)[keyof typeof ROLES];
function canDelete(role: Role): boolean {
return role === ROLES.Admin;
}as const also works on arrays: each element becomes a read-only literal, and (typeof SIZES)[number] produces the union of the values. A single source of truth feeds both the running code and the types.
const SIZES = ["sm", "md", "lg"] as const;
type Size = (typeof SIZES)[number];
function isSize(value: string): value is Size {
return (SIZES as readonly string[]).includes(value);
}