← Back to TypeScript Course | Chapter 23: Performance and Best Practices | Lesson 4 of 7

Readonly Best Practices

readonly communicates that a property should not be reassigned after initialization. Using readonly carefully can make APIs safer, clarify ownership, and prevent accidental mutation.

Readonly Properties

Mark a property readonly when it genuinely should never be reassigned after the object is constructed — this is especially valuable for identifiers, timestamps, and configuration values that are meant to be set once.

Example: Readonly Properties

typescript
interface User {
  readonly id: number;
  name: string;
}
const user: User = { id: 1, name: "Ravi" };
user.name = "Updated";
console.log(user);

Readonly Arrays

A readonly array type blocks any method that would mutate the array in place, like push or pop, at compile time — reach for it whenever a function is only supposed to read a collection, never modify it.

Example: Readonly Arrays

typescript
function printAll(items: readonly string[]) {
  console.log(items.join(", "));
}
printAll(["a", "b", "c"]);

Readonly Tuples

readonly tuples preserve both the tuple's fixed length and its readonly behavior together, which fits naturally for coordinates, key-value pairs, and other small, fixed-position data that shouldn't be resized or mutated.

Example: Readonly Tuples

typescript
const point: readonly [number, number] = [10, 20];
console.log(point[0], point[1]);

Readonly Parameters

Use readonly on function parameters when that function must not mutate whatever object or collection its caller passed in — this documents the function's contract directly at the type level instead of only in a comment.

Example: Readonly Parameters

typescript
function sum(numbers: readonly number[]): number {
  return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum([1, 2, 3]));

Readonly Is Not Deep Immutability

readonly only protects the property or the collection reference itself — it does not automatically make nested objects immutable too, so apply readonly recursively (or a dedicated deep-immutability type) when that's actually required.

Example: Readonly Is Not Deep Immutability

typescript
interface Address { city: string; }
interface User { readonly address: Address; }
const user: User = { address: { city: "Patna" } };
user.address.city = "Delhi"; // allowed -- readonly is shallow
console.log(user.address.city);
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.