TypeScript Enum vs Union Type: Which One Should You Use?
Problem
When defining a set of constants in TypeScript, you face the classic dilemma: enum or union type? Both work, but they have very different runtime behaviors.
The Enum Trap
enum Status {
Active = 'ACTIVE',
Inactive = 'INACTIVE',
Pending = 'PENDING'
}
This compiles to a runtime object in JavaScript:
var Status;
(function (Status) {
Status["Active"] = "ACTIVE";
Status["Inactive"] = "INACTIVE";
Status["Pending"] = "PENDING";
})(Status || (Status = {}));
That’s extra bundle size, and it doesn’t tree-shake well.
Solution: Union Type with as const
const STATUS = {
Active: 'ACTIVE',
Inactive: 'INACTIVE',
Pending: 'PENDING',
} as const;
type Status = typeof STATUS[keyof typeof STATUS];
// Result: 'ACTIVE' | 'INACTIVE' | 'PENDING'
With as const, TypeScript infers literal types. Minimal runtime footprint, excellent tree-shaking.
For simple cases, a plain union is even cleaner:
type Direction = 'up' | 'down' | 'left' | 'right';
Key Points
enumcreates a runtime object, increasing bundle sizeconst enumgets inlined but doesn’t work with--isolatedModules(Vite, Next.js)as const+ union type is the better default for most use cases- Use
enumonly when you need bitwise flags or runtime reverse mapping