Execute Program

Everyday TypeScript: Readonly

Welcome to the Readonly lesson!

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • We've seen the ReadonlyArray type. Sometimes we want to make objects read-only too. There are a few convenient ways to do that.

  • The first way is to make individual properties read-only by adding readonly to their property declarations. Any attempt to replace a readonly property is a type error.

  • >
    type User = {
    readonly name: string
    age: number
    };

    const amir: User = {name: 'Amir', age: 36};
    amir.name = 'Betty';
    amir;
    Result:
    type error: Cannot assign to 'name' because it is a read-only property.Pass Icon
  • >
    type User = {
    readonly name: string
    age: number
    };

    const amir: User = {name: 'Amir', age: 36};
    amir.age += 1;
    amir;
    Result:
    {name: 'Amir', age: 37}Pass Icon
  • The readonly syntax for properties also works in interfaces and classes.

  • >
    interface User {
    readonly name: string
    }

    const amir: User = {name: 'Amir'};
    amir.name = 'Betty';
    amir;
    Result:
    type error: Cannot assign to 'name' because it is a read-only property.Pass Icon
  • >
    class User {
    readonly name: string;

    constructor(name: string) {
    this.name = name;
    }
    }

    const amir = new User('Amir');
    amir.name = 'Betty';
    amir;
    Result:
    type error: Cannot assign to 'name' because it is a read-only property.Pass Icon
  • In the last example, our class's constructor assigned to the read-only name property by doing this.name = name. This is one case where we're allowed to write to a property even when it's read-only. If the constructor couldn't write to the read-only property then there would be no way to set the property's value at all!

  • What if we want to make the entire object type (that is, every property) read-only? For that, there's a second way: we can use Readonly<T>, a generic utility type. It automatically adds the readonly modifier that we saw above to every property in the type.

  • >
    type User = Readonly<{
    name: string
    age: number
    }>;

    const amir: User = {name: 'Amir', age: 36};
    amir.name = 'Betty';
    amir.name;
    Result:
    type error: Cannot assign to 'name' because it is a read-only property.Pass Icon
  • Unlike arrays, we can't specify a read-only object type with readonly User; that's a type error. We have to use Readonly<User> instead.

  • >
    type User = {
    name: string
    };

    const amir: readonly User = {name: 'Amir'};
    amir.name = 'Betty';
    amir.name;
    Result:
    type error: 'readonly' type modifier is only permitted on array and tuple literal types.Pass Icon
  • There are a lot of details around read-only data in TypeScript. Our recommendation is to always start by asking "what data should never change?" Then you can work out which TypeScript features solve that problem.

  • For example, Execute Program loads all of its courses when the backend server first boots. Then they stay in memory forever, unchanged, until the server shuts down.

  • We need to make sure that our code never accidentally changes that course data, for example by calling .sort() on an array. Based on that need, we've made all of the course data read-only using readonly, Readonly, and ReadonlyArray. Doing this work upfront might feel tedious, but it can prevent subtle bugs that would cause severe problems.