TypeScript
07 / 18

Enums & Literal Types

TypeScript Enums & Literal Types

Enums

Enums allow you to define a set of named constants, making it easier to document intent and create distinct cases.

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

let dir: Direction = Direction.Up;
console.log(dir); // 0
console.log(Direction[0]); // 'Up' (reverse mapping)

// Custom numeric values
enum HttpStatus {
  OK = 200,
  Created = 201,
  BadRequest = 400,
  Unauthorized = 401,
  NotFound = 404,
  ServerError = 500
}

function handleResponse(status: HttpStatus): void {
  switch (status) {
    case HttpStatus.OK:
      console.log('Success');
      break;
    case HttpStatus.NotFound:
      console.log('Resource not found');
      break;
    default:
      console.log('Other status');
  }
}

// String enum
enum LogLevel {
  Error = 'ERROR',
  Warning = 'WARNING',
  Info = 'INFO',
  Debug = 'DEBUG'
}

function log(level: LogLevel, message: string): void {
  console.log(`[${level}] ${message}`);
}

log(LogLevel.Error, 'Something went wrong');

// Const enum (inlined at compile time)
const enum Colors {
  Red = '#FF0000',
  Green = '#00FF00',
  Blue = '#0000FF'
}

const color = Colors.Red; // Inlined as '#FF0000'

// Heterogeneous enum (not recommended)
enum Mixed {
  No = 0,
  Yes = 'YES'
}

Literal Types

// String literals
type CardinalDirection = 'North' | 'South' | 'East' | 'West';
let direction: CardinalDirection = 'North';
// direction = 'Up'; // ❌ Error

// Number literals
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
let roll: DiceRoll = 4;
// roll = 7; // ❌ Error

// Boolean literals
type True = true;
type False = false;

// Template literal types
type Greeting = `Hello ${string}`;
const hi: Greeting = 'Hello World';  // ✅
// const bad: Greeting = 'Hi World';  // ❌ Error

type EventName = 'click' | 'focus' | 'blur';
type EventHandler = `on${Capitalize<EventName>}`;
// Result: 'onClick' | 'onFocus' | 'onBlur'

type PropEventSource<T> = {
  on<K extends string & keyof T>(eventName: `${K}Changed`, callback: (newValue: T[K]) => void): void;
};

// Literal inference
const req = { method: 'GET' as const }; // Type: { method: 'GET' }
// vs
const req2 = { method: 'GET' }; // Type: { method: string }

When to Use Enum vs Literal Types

  • Use Enums when: You need reverse mapping, want a runtime object, or need to iterate over values

  • Use Literal Types when: You want compile-time only types, smaller bundle size, or better tree-shaking

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free