runtime.boot

Full Stack Systems
Production Mindset

CodeWithMihir

Engineering thoughtful products from interface to infrastructure.

CodeWithMihir

TypeScript Tutorial

TypeScript Readonly Properties Explained with Examples

Learn how readonly properties work in TypeScript, including immutable object fields, readonly arrays, and common readonly mistakes.

Welcome back! I am Mihir, and in this lesson we will learn readonly properties in TypeScript.

readonly prevents accidental reassignment of object properties.


What is readonly?

Use readonly before a property name.

type User = {
  readonly id: number;
  name: string;
};

const user: User = {
  id: 1,
  name: "Mihir",
};

You can read id:

console.log(user.id);

But you cannot change it:

user.id = 2;

TypeScript warns because id is readonly.


Why Use readonly?

Use readonly for values that should not change after creation.

Common examples:

  • database IDs
  • created dates
  • configuration values
  • route names
  • fixed metadata

Example:

type BlogPost = {
  readonly slug: string;
  title: string;
  views: number;
};

The title and views may change, but the slug should stay stable.


readonly Does Not Freeze Runtime Objects

Important: readonly is a TypeScript check.

It does not freeze the object at runtime.

type User = {
  readonly id: number;
};

TypeScript prevents this during development:

user.id = 2;

But JavaScript itself still runs without TypeScript types after compilation.

If you need runtime immutability, use JavaScript tools like Object.freeze().


readonly with Nested Objects

readonly only applies to the property itself.

type User = {
  readonly profile: {
    bio: string;
  };
};

const user: User = {
  profile: {
    bio: "Developer",
  },
};

This is invalid:

user.profile = { bio: "Writer" };

But this is allowed:

user.profile.bio = "Writer";

The profile property is readonly, but the nested bio property is not.


Make Nested Properties readonly

If nested values should not change, mark them too.

type User = {
  readonly profile: {
    readonly bio: string;
  };
};

Now this is invalid:

user.profile.bio = "Writer";

readonly Arrays

You can make arrays readonly.

const roles: readonly string[] = ["admin", "editor", "viewer"];

Invalid:

roles.push("guest");
roles.pop();
roles[0] = "owner";

Readonly arrays can be read, but not mutated.


ReadonlyArray Syntax

This is another valid syntax:

const roles: ReadonlyArray<string> = ["admin", "editor", "viewer"];

Both are fine.

Most beginners find this shorter:

readonly string[]

readonly in Function Parameters

Readonly parameters protect input data from mutation.

function printRoles(roles: readonly string[]): void {
  roles.forEach((role) => console.log(role));
}

Inside the function, this is invalid:

roles.push("guest");

The function can read the array but cannot modify it.


Common Mistake: Expecting Deep Immutability

This is not deeply readonly:

type Settings = {
  readonly theme: {
    mode: string;
  };
};

Only theme itself cannot be replaced. theme.mode can still change.

Mark nested properties as readonly if needed.


Quick Reference Summary

ConceptExample
Readonly propertyreadonly id: number
Cannot reassignuser.id = 2 is invalid
Readonly arrayreadonly string[]
Alternate syntaxReadonlyArray<string>
Runtime freezeuse Object.freeze()
Not deep by defaultnested fields need readonly too

Practice

Create a readonly product ID:

type Product = {
  readonly id: number;
  title: string;
  price: number;
};

const product: Product = {
  id: 1,
  title: "Keyboard",
  price: 1499,
};

product.title = "Mechanical Keyboard";

Now try changing product.id and check TypeScript's warning.


What You've Learned

You now understand:

  • What readonly means
  • How readonly properties prevent reassignment
  • When readonly properties are useful
  • Why readonly is a TypeScript check, not a runtime freeze
  • How readonly works with nested objects
  • How readonly arrays work
  • How to use readonly function parameters

What's Next?

In the next lesson, we will learn Union and Literal Types in TypeScript.

We will model values that can be one of several possible options.


Need Help?

  • Have questions, confusion, or want to know more? Contact me

readonly is a small keyword with a big job: it protects values that should stay stable.