Compare numeric and string Enums against modern const assertions (as const) for defining clean constant dictionaries.
Discover how TypeScript infers types automatically and how let versus const declarations shape wide types versus narrow literal types.
In software engineering, you often need to group named constant values together (such as HTTP status codes, user roles, or payment states).
TypeScript provides the enum keyword for defining named constants:
// String Enum
enum UserRole {
Admin = "ADMIN",
Editor = "EDITOR",
Viewer = "VIEWER",
}
function checkAccess(role: UserRole) {
if (role === UserRole.Admin) {
console.log("Full access granted.");
}
}
as const (Const Assertions)While Enums generate extra JavaScript code during compilation, Const Assertions (as const) create zero-overhead runtime objects with narrow literal types:
// Plain JavaScript object with 'as const' assertion
const USER_ROLES = {
Admin: "ADMIN",
Editor: "EDITOR",
Viewer: "VIEWER",
} as const;
// Extract union type from the object values
type Role = typeof USER_ROLES[keyof typeof USER_ROLES]; // "ADMIN" | "EDITOR" | "VIEWER"
function setRole(r: Role) {
console.log("Setting role to:", r);
}
setRole(USER_ROLES.Admin); // Valid!
| Feature | Enum | Const Assertion (as const) |
|---|---|---|
| Runtime JS Output | Generates IIFE object code | Generates plain JS object |
| Type Narrowing | Nominal Enum type | Literal Union type |
| Tree-Shaking | Harder for bundlers | 100% Tree-shakable |
enum Status { Pending, Active }) generate reverse mapping objects at runtime, making them accept arbitrary numbers without type warnings! Default to string enums or as const.Use as const for clean, tree-shakable constants. Next, let's explore Literal Types and Template Literal Types!