Enums, Tuples & Special Types

0/6 in this phase0/21 across the roadmap

📖 Concept

Enums define a set of named constants. TypeScript has numeric enums, string enums, and const enums.

Tuples are fixed-length arrays where each position has a specific type. They're like arrays with a known structure.

Special types round out TypeScript's type system — as const, assertion functions, branded types, and more.

Enum debate: Many TypeScript experts (including the TS team) now recommend union literal types or as const objects over enums because:

  • Enums generate runtime JavaScript code (they're not type-only)
  • const enum is fragile across module boundaries
  • Union literals are zero-cost and tree-shakeable

Tuples are critical for:

  • React hooks: useState returns [T, SetterFn]
  • Coordinate data: [number, number]
  • Function overloads with variadic args
  • Named tuples for readability: [name: string, age: number]

as const creates the narrowest possible type — all properties become readonly and values become literal types. This is how you create type-safe constant objects.

🏠 Real-world analogy: An enum is like a menu with numbered items — "1. Coffee, 2. Tea, 3. Water". as const is like a menu printed on a brass plaque — it's fixed, permanent, and everyone sees exactly the same options.

💻 Code Example

codeTap to expand ⛶
1// Numeric Enum (auto-increments from 0)
2enum Direction {
3 Up, // 0
4 Down, // 1
5 Left, // 2
6 Right // 3
7}
8console.log(Direction.Up); // 0
9console.log(Direction[0]); // "Up" (reverse mapping)
10
11// String Enum (recommended over numeric)
12enum Status {
13 Active = "ACTIVE",
14 Inactive = "INACTIVE",
15 Pending = "PENDING"
16}
17
18// ⚠️ Enums generate runtime code:
19// var Status;
20// (function (Status) {
21// Status["Active"] = "ACTIVE";
22// ...
23// })(Status || (Status = {}));
24
25// ✅ Better alternative: union literal types (zero-cost)
26type StatusType = "ACTIVE" | "INACTIVE" | "PENDING";
27
28// ✅ Or: as const object (runtime values + type safety)
29const STATUS = {
30 Active: "ACTIVE",
31 Inactive: "INACTIVE",
32 Pending: "PENDING"
33} as const;
34type StatusValue = typeof STATUS[keyof typeof STATUS];
35// "ACTIVE" | "INACTIVE" | "PENDING"
36
37// Tuples — fixed length, typed positions
38let point: [number, number] = [10, 20];
39let entry: [string, number] = ["age", 30];
40
41// Named tuples (TypeScript 4.0+) — for readability
42type UserTuple = [name: string, age: number, active: boolean];
43const user: UserTuple = ["Alice", 30, true];
44
45// Rest elements in tuples
46type StringAndNumbers = [string, ...number[]];
47const data: StringAndNumbers = ["scores", 90, 85, 95];
48
49// React useState pattern
50function useState<T>(initial: T): [T, (value: T) => void] {
51 let state = initial;
52 const setState = (value: T) => { state = value; };
53 return [state, setState];
54}
55const [count, setCount] = useState(0); // Properly typed!
56
57// as const — creates the narrowest type
58const CONFIG = {
59 api: "https://api.example.com",
60 timeout: 5000,
61 retries: 3,
62 methods: ["GET", "POST"] // readonly ["GET", "POST"], not string[]
63} as const;
64// CONFIG.timeout = 10000; // ❌ Error: readonly
65// type: { readonly api: "https://..."; readonly timeout: 5000; ... }
66
67// Const assertions with arrays
68const ROLES = ["admin", "editor", "viewer"] as const;
69type Role = typeof ROLES[number]; // "admin" | "editor" | "viewer"
70
71// Assertion functions
72function assertIsString(value: unknown): asserts value is string {
73 if (typeof value !== "string") {
74 throw new Error(`Expected string, got ${typeof value}`);
75 }
76}
77function process(input: unknown) {
78 assertIsString(input);
79 console.log(input.toUpperCase()); // TS knows input is string!
80}

🏋️ Practice Exercise

Mini Exercise:

  1. Create both an enum and an as const object for roles — compare the compiled JavaScript output
  2. Declare a tuple type for a database row: [id: number, name: string, email: string, active: boolean]
  3. Use as const to create a readonly config object and derive a union type from its values
  4. Write an assertion function assertNonNull<T>(value: T | null): asserts value is T
  5. Use rest elements in a tuple: [first: string, ...rest: number[]]

⚠️ Common Mistakes

  • Using numeric enums with 0 as a value — 0 is falsy, leading to bugs like if (role) failing for the first enum member

  • Not knowing enums generate runtime JavaScript — unlike types/interfaces, enums are NOT erased at compile time

  • Using const enum across module boundaries — it can cause issues with declaration files and some bundlers (e.g., isolatedModules)

  • Thinking tuples can have any length — tuples have a FIXED length; TypeScript will error if you try to access beyond the declared positions

  • Forgetting as const on object literals — without it, { role: 'admin' } has type { role: string } instead of { role: 'admin' }

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for Enums, Tuples & Special Types