On this page
Arrays, tuples, and enums
Typed arrays
Arrays in TypeScript are typed collections where every element has the same type. TypeScript provides two syntaxes for declaring array types — they are completely equivalent, and which you use is a matter of style:
const scores: number[] = [100, 87, 95]; // shorthand syntax
const names: Array<string> = ["Alice", "Bob"]; // generic syntaxThe generic syntax Array<T> looks more consistent with other generic types. The shorthand T[] is more concise and is preferred by most style guides. This course uses the shorthand.
Readonly arrays
Arrays are mutable by default. If you want to prevent modification — an essential technique for working with configuration, constants, or data you pass to external systems — use readonly:
const SUPPORTED_LOCALES: readonly string[] = ["en", "es", "fr", "de"];
// All of these are compile errors:
SUPPORTED_LOCALES.push("ja"); // cannot add
SUPPORTED_LOCALES.pop(); // cannot remove
SUPPORTED_LOCALES[0] = "zh"; // cannot modify
SUPPORTED_LOCALES.sort(); // cannot sort (mutates in place)
// Reading is always allowed:
const first = SUPPORTED_LOCALES[0]; // "en"
const count = SUPPORTED_LOCALES.length; // 4ReadonlyArray<T> is the long form and is identical in behaviour to readonly T[].
Typed arrays in practice
When you iterate or map over a typed array, TypeScript infers the element type automatically:
const prices: number[] = [9.99, 14.99, 4.99];
// item is inferred as number — no annotation needed
const discounted = prices.map((item) => item * 0.9);
// TypeScript catches invalid operations on the element type
const lengths = prices.map((item) => item.toUpperCase()); // Error: 'toUpperCase' does not exist on 'number'Tuples
A tuple is a fixed-length array where each position has its own specific type. Where an array says "a list of values all of the same type", a tuple says "exactly N values, each with a defined type at a specific index".
// A coordinate pair: [x, y]
type Point2D = [number, number];
const origin: Point2D = [0, 0];
const cursor: Point2D = [42, 17];
// Length and types are enforced
const invalid: Point2D = [0, 0, 0]; // Error: Source has 3 element(s) but target allows only 2
const alsoInvalid: Point2D = [0, "y"]; // Error: Type 'string' is not assignable to type 'number'Named tuples
Named tuples label each element without changing the type. They make tuple types self-documenting and improve the hover text in editors:
type DateRange = [start: Date, end: Date];
type RGBColor = [red: number, green: number, blue: number];
const range: DateRange = [new Date("2026-01-01"), new Date("2026-12-31")];
const white: RGBColor = [255, 255, 255];
// Destructuring uses the declared names as hints (optional)
const [start, end] = range;Tuple use cases
Tuples are commonly used for:
- Return values from functions where a specific structure is expected
- React-style hook patterns that return
[value, setter] - CSV/table row data where each column has a known type
// Hook-style function returning a tuple
function useCounter(initial: number): [count: number, increment: () => void, reset: () => void] {
let count = initial;
return [
count,
() => { count++; },
() => { count = initial; },
];
}
const [count, increment, reset] = useCounter(0);Optional and rest elements in tuples
Tuples can have optional trailing elements (marked with ?) and rest elements:
// Optional last element
type Pair = [string, string?];
const solo: Pair = ["alone"]; // second element omitted
const duo: Pair = ["first", "second"];
// Rest element — zero or more strings after the first number
type LogEntry = [timestamp: number, ...messages: string[]];
const entry: LogEntry = [1712345678, "Server started", "Listening on port 3000"];Enums
Enums define a named set of constants. They are the one TypeScript feature that has no direct JavaScript equivalent — enums generate real JavaScript code.
String enums
String enums give each member an explicit string value. They are the most common and safest kind of enum:
enum LogLevel {
Debug = "DEBUG",
Info = "INFO",
Warning = "WARNING",
Error = "ERROR",
}
function log(level: LogLevel, message: string): void {
console.log(`[${level}] ${message}`);
}
log(LogLevel.Info, "Server started"); // [INFO] Server started
log("INFO", "Server started"); // Error: Argument of type '"INFO"' is not assignable to parameter of type 'LogLevel'The last line is an important safety feature: TypeScript refuses to accept a bare string even if its value matches an enum member. You must use the enum reference.
Numeric enums
Numeric enums assign integer values starting from 0 by default. You can override the starting value:
enum HttpStatus {
Ok = 200,
Created = 201,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
InternalServerError = 500,
}
function handleResponse(status: HttpStatus): void {
if (status === HttpStatus.Ok || status === HttpStatus.Created) {
console.log("Success");
} else if (status >= 400) {
console.log("Error");
}
}const enums
const enum members are inlined at every usage point during compilation. The enum itself disappears from the output, producing smaller and faster code:
const enum Alignment {
Left = "LEFT",
Center = "CENTER",
Right = "RIGHT",
}
const textAlign = Alignment.Center;
// Compiles to: const textAlign = "CENTER";
// No enum object exists at runtimeThe tradeoff: const enum values cannot be iterated at runtime because the enum object does not exist.
Enums vs union literals
For most use cases, a union of string literals is a better choice than an enum:
// Enum approach
enum Status { Active = "active", Inactive = "inactive", Pending = "pending" }
// Union literal approach — simpler, no compile output, JSON-compatible
type Status = "active" | "inactive" | "pending";Use enums when you need:
- The enum object at runtime (e.g., to iterate all values)
- Interoperability with code generators (Prisma, OpenAPI tools, gRPC)
- Bitfield flags (
const enum Permissions { Read = 1, Write = 2, Execute = 4 })
Use union literals for everything else.
Practice
- Create a readonly array of supported themes (
"light" | "dark" | "system"). Write a function that accepts a theme and returns a CSS class name. Verify that passing an unsupported string is a compile error. - Define a named tuple
ApiResultwith fields[status: number, data: unknown, error?: string]. Write a function that returns this tuple and destructure the result at the call site. - Convert an enum you find in an existing codebase (or write a new one) to a union literal type. Verify that all existing usages still compile correctly.
// Typed arrays — two equivalent syntaxes
const scores: number[] = [95, 87, 72];
const names: Array<string> = ["Alice", "Bob", "Carol"];
// Readonly array — elements cannot be added, removed, or replaced
const config: readonly string[] = ["dark", "compact", "rtl"];
config.push("new"); // Error: Property 'push' does not exist on type 'readonly string[]'
config[0] = "light"; // Error: Index signature in type 'readonly string[]' only permits reading
// ReadonlyArray<T> is equivalent to readonly T[]
const ids: ReadonlyArray<number> = [1, 2, 3];
Sign in to track your progress