TypeScript Cheatsheet

Enums

Use this TypeScript reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Numeric Enums

// Members auto-increment from 0 by default
enum Direction {
  Up,     // 0
  Down,   // 1
  Left,   // 2
  Right,  // 3
}

// Custom starting value
enum Status {
  Pending = 1,
  Active,   // 2
  Inactive, // 3
}

// Custom value for each member
enum HttpStatus {
  OK          = 200,
  Created     = 201,
  BadRequest  = 400,
  Unauthorized = 401,
  NotFound    = 404,
  ServerError = 500,
}

const dir: Direction = Direction.Up; // 0
const code: HttpStatus = HttpStatus.OK; // 200

String Enums

// Each member must have a string literal value
enum Color {
  Red   = "RED",
  Green = "GREEN",
  Blue  = "BLUE",
}

enum LogLevel {
  Debug = "debug",
  Info  = "info",
  Warn  = "warn",
  Error = "error",
}

const level: LogLevel = LogLevel.Warn; // "warn"

// String enums are NOT reverse-mappable (unlike numeric)
// LogLevel["warn"] doesn't give you LogLevel.Warn

Heterogeneous Enums (Avoid)

// Mixing string and number members is allowed but discouraged
enum Mixed {
  No  = 0,
  Yes = "YES",
}
// Avoid this pattern — it's confusing and rarely useful

Const Enums

// Inlined at compile time — no runtime object generated
const enum Axis {
  X,   // 0
  Y,   // 1
  Z,   // 2
}

let axis = Axis.X; // compiles to: let axis = 0;

// Benefit: zero runtime overhead
// Tradeoff: can't use Axis as a value (no Object.values(Axis)), can't use with --isolatedModules if from another file

const enum Permission {
  Read    = 1 << 0,  // 1
  Write   = 1 << 1,  // 2
  Execute = 1 << 2,  // 4
}

Ambient Enums

// declare enum — describes an enum that exists in another context (e.g., a .d.ts)
declare enum ExternalStatus {
  Active,
  Inactive,
}

// declare const enum — for declaration files
declare const enum ExternalCode {
  A = 1,
  B = 2,
}

Enum as Type

enum Suit {
  Clubs    = "CLUBS",
  Diamonds = "DIAMONDS",
  Hearts   = "HEARTS",
  Spades   = "SPADES",
}

// Enum type can be used like any type
function playCard(suit: Suit): void {
  console.log(suit);
}
playCard(Suit.Hearts);
// playCard("HEARTS"); // Error — must use enum member

// Enum member type
type Hearts = Suit.Hearts; // the literal type "HEARTS"

Reverse Mapping (Numeric Enums Only)

enum Direction {
  Up = 0,
  Down = 1,
}

Direction.Up;        // 0
Direction[0];        // "Up"   ← reverse mapping
Direction[Direction.Up]; // "Up"

// Not available for string enums
enum Color { Red = "RED" }
// Color["RED"] — undefined (no reverse map for string enums)

Enum Iteration

enum Role {
  Admin = "ADMIN",
  User  = "USER",
  Guest = "GUEST",
}

// Iterating string enum values
Object.values(Role).forEach(r => console.log(r));
// "ADMIN", "USER", "GUEST"

// Iterating numeric enum (includes reverse mapping entries — filter needed)
enum Status { Active, Inactive }
const numericValues = Object.values(Status)
  .filter((v): v is number => typeof v === "number");
// [0, 1]

// Keys of numeric enum
const numericKeys = Object.keys(Status)
  .filter(k => isNaN(Number(k)));
// ["Active", "Inactive"]

Enum Member Types and Union

// Each member of a literal enum becomes its own type
enum ShapeKind {
  Circle,
  Square,
}

interface Circle {
  kind: ShapeKind.Circle;
  radius: number;
}

interface Square {
  kind: ShapeKind.Square;
  side: number;
}

type Shape = Circle | Square;

function area(s: Shape) {
  switch (s.kind) {
    case ShapeKind.Circle: return Math.PI * s.radius ** 2;
    case ShapeKind.Square: return s.side ** 2;
  }
}

Bitwise / Flags Enum Pattern

enum FilePermission {
  None    = 0,
  Read    = 1 << 0,  // 1
  Write   = 1 << 1,  // 2
  Execute = 1 << 2,  // 4
  All     = Read | Write | Execute, // 7
}

// Combine flags
const userPerms = FilePermission.Read | FilePermission.Write; // 3

// Check flag
function hasPermission(perms: FilePermission, flag: FilePermission): boolean {
  return (perms & flag) === flag;
}
hasPermission(userPerms, FilePermission.Read);    // true
hasPermission(userPerms, FilePermission.Execute); // false

// Add flag
const newPerms = userPerms | FilePermission.Execute; // 7

// Remove flag
const reduced = userPerms & ~FilePermission.Write; // 1

Enum vs as const Object Pattern

// Enum — generates a real runtime object and a type
enum DirectionEnum {
  Up = "UP",
  Down = "DOWN",
}

// as const — plain object with no enum overhead; more tree-shakeable
const Direction = {
  Up:   "UP",
  Down: "DOWN",
} as const;

type Direction = typeof Direction[keyof typeof Direction]; // "UP" | "DOWN"

// Usage is nearly identical
const go = (dir: Direction) => console.log(dir);
go(Direction.Up);

// Advantages of as const over enum:
// - No runtime enum object bloat (tree-shakeable)
// - Works with --isolatedModules
// - Integrates seamlessly with string union types
// - More predictable in module resolution

Exhaustiveness Checking with Enums

enum Fruit {
  Apple,
  Banana,
  Cherry,
}

function describe(f: Fruit): string {
  switch (f) {
    case Fruit.Apple:  return "apple";
    case Fruit.Banana: return "banana";
    case Fruit.Cherry: return "cherry";
    default:
      const _exhaustive: never = f; // Error if a case is missing
      return _exhaustive;
  }
}

Enums in Function Parameters and Guards

enum Status {
  Active   = "active",
  Inactive = "inactive",
  Pending  = "pending",
}

// Type guard to check if a string is a valid Status
function isStatus(val: string): val is Status {
  return Object.values(Status).includes(val as Status);
}

// Parse unknown string
function parseStatus(val: string): Status {
  if (!isStatus(val)) throw new Error(`Invalid status: ${val}`);
  return val;
}

// Enum as record key
const statusLabels: Record<Status, string> = {
  [Status.Active]:   "Active",
  [Status.Inactive]: "Inactive",
  [Status.Pending]:  "Pending",
};