Skip to content
⚠️ This article was written in 2018. Some content may be outdated.

TypeScript Enums and Namespaces

TypeScript enums are a must-have for developers coming from Java or C#, but there are some important nuances in TS. Namespaces are used less often but still have the right use cases.

Numeric Enums

typescript
enum Direction {
  Up, // 0
  Down, // 1
  Left, // 2
  Right, // 3
}

console.log(Direction.Up); // 0
console.log(Direction[0]); // 'Up' (reverse mapping)

Numeric enums create a bidirectional mapping (value→name, name→value), so the compiled output is larger.

typescript
enum Status {
  Pending = "PENDING",
  Active = "ACTIVE",
  Disabled = "DISABLED",
}

// Advantage: human-readable when debugging, not meaningless numbers like 0/1/2
console.log(Status.Active); // 'ACTIVE'

// Usage
function updateUser(status: Status) {
  api.patch("/user", { status });
}
updateUser(Status.Active);

const enum: Compile-time Inlining

typescript
// A regular enum compiles to an object at runtime
// const enum values are inlined at compile time (smaller bundle)
const enum Direction {
  Up = "UP",
  Down = "DOWN",
}

const dir = Direction.Up;
// Compiled: const dir = 'UP' (inlined — no object)

Note: const enum does not support reverse mapping and cannot be used with Object.values(Direction).

Modern Alternatives to Enums

Many scenarios can use union types instead of enums:

typescript
// Enum approach
enum Status {
  Active = "ACTIVE",
  Disabled = "DISABLED",
}

// Union type approach (more concise)
type Status = "ACTIVE" | "DISABLED";

// Or use an `as const` object (allows Object.values)
const STATUS = {
  Active: "ACTIVE",
  Disabled: "DISABLED",
} as const;

type Status = (typeof STATUS)[keyof typeof STATUS]; // 'ACTIVE' | 'DISABLED'

// Get all values
Object.values(STATUS); // ['ACTIVE', 'DISABLED']

Namespaces

Namespaces were used to organize code before ES6 modules became widespread. Today they're primarily useful for writing type declaration files for third-party JavaScript libraries:

typescript
// Declare a global variable on window
declare namespace window {
  const __CONFIG__: {
    apiUrl: string;
    version: string;
  };
}

// Usage
console.log(window.__CONFIG__.apiUrl);
typescript
// Writing type declarations for a global library like jQuery
declare namespace $ {
  function ajax(url: string, options?: object): Promise<any>;
  namespace fn {
    function extend(plugin: object): void;
  }
}

Practical Project Recommendations

typescript
// API status and similar: use string literal union types
type ApiStatus = "idle" | "loading" | "success" | "error";

// When you need to iterate all values: use an as const object
const ROLES = {
  Admin: "admin",
  Editor: "editor",
  Viewer: "viewer",
} as const;

// When you need reverse mapping: use a regular enum
enum HttpMethod {
  GET = "GET",
  POST = "POST",
  PUT = "PUT",
  DELETE = "DELETE",
}

Summary

  • Numeric enums: have reverse mapping, but numbers are hard to read
  • String enums: human-readable, recommended
  • const enum: compile-time inlining, smaller bundle, but with limitations
  • Namespaces: mainly used for global library type declarations today; use ES modules for new code

MIT Licensed