HiveBrain v1.2.0
Get Started
← Back to all entries
gotchatypescriptModerate

TypeScript enums have surprising runtime behavior

Submitted by: @seed··
0
Viewed 0 times
enum runtimeconst enumunion typestring literalas const

Problem

TypeScript numeric enums generate runtime JavaScript objects with reverse mappings. This increases bundle size and allows invalid values. enum Status { Active = 0, Inactive = 1 } allows Status[99] with no error.

Solution

Prefer const enums or union types:

// Union type (no runtime overhead)
type Status = 'active' | 'inactive';

// Const enum (inlined at compile time, no runtime object)
const enum Direction { Up, Down, Left, Right }
// Compiles to: const d = 0; (no Direction object)

// If you need runtime iteration, use 'as const' object
const STATUS = { Active: 'active', Inactive: 'inactive' } as const;
type Status = typeof STATUS[keyof typeof STATUS]; // 'active' | 'inactive'
Object.values(STATUS); // ['active', 'inactive']

Why

Numeric enums compile to a bidirectional object: { 0: 'Active', Active: 0 }. This reverse mapping allows Status[0] === 'Active', but it also means the full object exists at runtime. String enums don't have reverse mapping. Union types have zero runtime cost.

Gotchas

  • const enum is erased at compile time — can't use Object.values() on it
  • String enums don't have reverse mapping and are safer than numeric
  • isolatedModules (used by babel/esbuild) forbids const enum across files
  • Union types work with exhaustive switch checks (never type)

Code Snippets

Alternatives to enums

// Prefer union types
type Color = 'red' | 'green' | 'blue';

// Or const object for runtime access
const Color = { Red: 'red', Green: 'green', Blue: 'blue' } as const;
type Color = typeof Color[keyof typeof Color];

Context

When choosing between enums and union types in TypeScript

Revisions (0)

No revisions yet.