DEV Community

Cover image for TypeScript and the ReadOnly option
Chris Bongers
Chris Bongers

Posted on • Originally published at daily-dev-tips.com

TypeScript and the ReadOnly option

When it comes to TypeScript, there is yet another modifier we haven't touched. This is readonly, which can be used to make fields read-only.

Meaning we are not allowed to change them after they initialize.

To demonstrate how it works, we'll look at how we can define interface properties as read-only and how we can alter those later on.

TypeScript readonly interface

The cool part about the readonly modifier is that we can even use it on the interface declaration, making specific fields read-only from the start.

It works by prefixing the type with readonly like this:

interface User {
  readonly id?: number;
  firstname: string;
  lastname: string;
  age?: number;
}
Enter fullscreen mode Exit fullscreen mode

The only time we can ever set this value is on initialising it like this:

const user:User = {
  id: 123,
  firstname: 'Felix',
  lastname: 'Bongers'
}
Enter fullscreen mode Exit fullscreen mode

As you know, we can change the firstname field, for instance:

user.firstname = 'Chris'
Enter fullscreen mode Exit fullscreen mode

But when we try and modify the ID field, we get an error.

user.id = 12
Enter fullscreen mode Exit fullscreen mode

TypeScript readonly error

This can be super useful for fields that you want to ensure can never change.

TypeScript ReadOnly utility type

We can also leverage a utility type to change a property to read-only.

We had a specific look at this in the article on TypeScript Readonly Utility Type.

However, now that we also learned how to leverage Pick and Omit, we can narrow down the use case.

Let's say we have this User interface again but only want to make the ID read-only at a later stage.

interface User {
  id?: number;
  firstname: string;
  lastname: string;
  age?: number;
}
Enter fullscreen mode Exit fullscreen mode

Now we could simply use the hack we used for Generics and Utility Types like this:

type IdReadOnly = Readonly<Pick<User, 'id'>> & Omit<User, 'id'>;
Enter fullscreen mode Exit fullscreen mode

Or even make this a generic re-usable type.

type ReadOnlyByKey<T, K extends keyof T> = Readonly<Pick<T, K>> & Omit<T, K>;
Enter fullscreen mode Exit fullscreen mode

Which in return we can use like this:

type IdReadOnly = ReadOnlyByKey<User, 'id'>;
Enter fullscreen mode Exit fullscreen mode

All these versions will make the id field read-only from that type on.

Removing the read-only modifier

There might be cases where you want to undo the read-only modifier.
And this particular removal is unique to the read-only property.

This is called mapping modifiers, and there are only two of them: readonly and ? (optional).

For instance to remove all occurrences of a readonly attribute we can do the following:

type Mutable<T> = {
   -readonly [k in keyof T]: T[k];
};
Enter fullscreen mode Exit fullscreen mode

This removes all readonly attributes since we used the - sign.
If you removed the -, all fields would be read-only.

Let's try this out for a second and take the first example we had.

interface User {
  readonly id?: number;
  firstname: string;
  lastname: string;
  age?: number;
}
Enter fullscreen mode Exit fullscreen mode

Before, we could not modify the id field, so let's convert this into a mutable type.

type Mutable<T> = {
  -readonly [k in keyof T]: T[k];
};

const user:Mutable<User> = {
  id: 123,
  firstname: 'Felix',
  lastname: 'Bongers'
}
Enter fullscreen mode Exit fullscreen mode

And now we can modify the id field again!

I hope you learned a lot about changing the read-only property of a type/interface.
Do let me know if you have any questions in this regard.

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

Top comments (0)