Notifications

No notifications

/Phase 1

Arrays, Tuples & Enums

Arrays in TS look exactly like JS arrays β€” but TS adds a layer that says *what's inside*. Tuples take it further: fixed length, fixed types per slot. Enums let you give names to a finite set of values, though modern TS often prefers literal-union types instead.

On this page

Detailed Theory

Typing arrays

Two equivalent syntaxes:

const ids: number[] = [1, 2, 3];
const names: Array<string> = ["Ada", "Linus"];

Use T[] for simple types, Array when T is itself complex (e.g. Array<{ id: number; name: string }>).

Mixed arrays β€” union element types

const mixed: (string | number)[] = [1, "two", 3];

Inference traps

const items = [];        // any[]  β€” TS can't infer
items.push(1);           // still any[] in older versions

const fruits = ["apple", "banana"]; // string[] fruits.push(1); // ❌

> If you see a mysterious any[] you didn't ask for, annotate the empty literal: const items: number[] = [].

readonly arrays

const colors: readonly string[] = ["red", "green"];
// colors.push("blue"); // ❌ push doesn't exist on readonly arrays

Use this on function parameters when you don't intend to mutate β€” it's a contract that says "I won't touch your array".

function sum(xs: readonly number[]): number {
  return xs.reduce((a, b) => a + b, 0);
}

Tuples β€” fixed length, fixed types

A tuple is an array where each *position* has its own type.

let pair: [string, number] = ["age", 21];
pair = [21, "age"]; // ❌ wrong order

Labelled tuples (TS 4.0+)

Labels are documentation β€” they don't change behaviour.

type Range = [start: number, end: number];
const r: Range = [0, 100];

Optional & rest elements

type Args = [name: string, age?: number];        // 1 or 2 items
type StartWithStr = [string, ...number[]];       // first must be string

When tuples shine

  • Returning multiple values from a function (React's useState is a tuple!)
  • Function arguments via spread
function useState<T>(initial: T): [T, (next: T) => void] {
  let v = initial;
  return [v, (next) => { v = next; }];
}
const [count, setCount] = useState(0); // count: number, setCount: (n: number) => void

readonly tuples & as const

const point = [1, 2] as const;     // readonly [1, 2]
type Point = typeof point;          // readonly [1, 2]

Enums

Enums give a name to a fixed set of values. There are three flavours:

1. Numeric enum (default)

enum Direction { Up, Down, Left, Right }
// Up=0, Down=1, Left=2, Right=3
const d: Direction = Direction.Up;

You can set the starting number; the rest auto-increment.

enum Status { Active = 1, Inactive, Banned } // 1, 2, 3

2. String enum

enum Theme {
  Light = "light",
  Dark = "dark",
  System = "system",
}

Easier to debug β€” log values are readable strings, not numbers.

3. const enum β€” inlined at compile time

const enum Level { Low, High }
// usage Level.Low compiles directly to 0 β€” no enum object emitted

Why many teams skip enums

Enums emit JS code (an object). Modern TS often prefers a literal-union type with as const:

const Theme = { Light: "light", Dark: "dark", System: "system" } as const;
type Theme = typeof Theme[keyof typeof Theme]; // "light" 
"dark""system"

Same autocomplete, zero runtime overhead, plays nicely with JSON. Use enums when you need the bidirectional name↔value lookup that numeric enums give you.

Quick reference

WantUse
List of one typeT[]
Generic / nestedArray
Promise NOT to mutatereadonly T[]
Fixed shape with positions[T1, T2, T3]
Returning multiple valuesTuple
Named, finite value setString enum or literal union