Difficulty: Beginner
TypeScript provides two syntaxes for typed arrays: `type[]` and `Array<type>`. Both are equivalent - `number[]` and `Array<number>` describe the same type. The bracket syntax is more common and concise, while the generic syntax is useful in certain contexts like when the element type itself is complex. A typed array ensures that every element conforms to the specified type, and all array methods (push, map, filter, etc.) respect the element type.
Tuples are a distinct concept from arrays. While an array has a variable length and a single element type (or union type), a tuple has a fixed length where each position has its own specific type. You define a tuple type as `[string, number, boolean]`, which means exactly three elements of those exact types in that exact order. Tuples are useful for representing structured data like coordinate pairs `[number, number]`, key-value pairs `[string, unknown]`, or function return values that carry multiple pieces of information.
TypeScript also supports readonly arrays and tuples via the `readonly` modifier or `ReadonlyArray<T>` generic. A `readonly number[]` prevents any mutations - you cannot push, pop, splice, or reassign elements. This is valuable for functional programming patterns where immutability is desired. Note that readonly arrays are a supertype of mutable arrays, so you can pass a mutable array where a readonly one is expected, but not vice versa.
Array types interact well with TypeScript's type inference. When you write `const nums = [1, 2, 3]`, TypeScript infers `number[]`. For tuples, you typically need explicit annotation since TypeScript defaults to inferring an array type: `const pair = [1, "hello"]` is inferred as `(string | number)[]`, not `[number, string]`. Use `as const` or an explicit tuple annotation to get the tuple type.
const numbers: number[] = [10, 20, 30, 40, 50];
const names: Array<string> = ["Alice", "Bob", "Charlie"];
// Array methods preserve type information
const doubled = numbers.map(n => n * 2); // number[]
const long = names.filter(n => n.length > 3); // string[]
const total = numbers.reduce((a, b) => a + b, 0); // number
console.log(doubled.join(", "));
console.log(long.join(", "));
console.log(total);
Both `type[]` and `Array<type>` syntax work identically. Array methods like map, filter, and reduce are fully typed - TypeScript knows the return types automatically.
// A tuple with specific types at each position
const userEntry: [string, number, boolean] = ["Alice", 30, true];
// Destructuring tuples gives typed variables
const [name, age, active] = userEntry;
console.log(`${name} is ${age}, active: ${active}`);
// Tuples as function return types
function divide(a: number, b: number): [number, number] {
return [Math.floor(a / b), a % b]; // [quotient, remainder]
}
const [quotient, remainder] = divide(17, 5);
console.log(`17 / 5 = ${quotient} remainder ${remainder}`);
Tuples enforce fixed length and per-position types. Destructuring a tuple gives each variable its correct type. Functions can return tuples to provide multiple typed return values.
const readonlyNums: readonly number[] = [1, 2, 3, 4, 5];
// readonlyNums.push(6); // Error: Property 'push' does not exist on readonly number[]
// readonlyNums[0] = 99; // Error: Index signature in type 'readonly number[]' only permits reading
// Readonly still allows non-mutating methods
const filtered = readonlyNums.filter(n => n > 2);
const mapped = readonlyNums.map(n => n * 10);
console.log("Filtered:", filtered.join(", "));
console.log("Mapped:", mapped.join(", "));
console.log("Original:", readonlyNums.join(", "));
Readonly arrays prevent mutations like push, pop, and direct index assignment. Non-mutating methods like filter and map still work and return new (mutable) arrays.
Typed arrays, Tuples, Readonly arrays, Array methods with types