← 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.
Syntax
typescript
interface TypeName {
    readonly propertyName: type;
}

const list: readonly type[] = [item1, item2];
const tuple: readonly [type, type] = [a, b];

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);
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Marking every property readonly including ones that need to change, then working around it with casts.
  2. Assuming readonly protects nested objects and arrays inside the object.
  3. Using readonly on a parameter and then still calling push on it, which is a compile error.
🔒

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.