Typescript Icon Get 42% off the TypeScript bundle

See the bundle then add to cart and your discount is applied.

0 days
00 hours
00 mins
00 secs

Write TypeScript like a pro. Typescript Icon

Follow the ultimate TypeScript roadmap.

Readonly Mapped Type in TypeScript

In this post you’ll learn how and when to use the Readonly mapped type TypeScript.

Mapped types are a newer feature of TypeScript and act as a dynamic construct to create new types from existing ones.

The way that the Readonly mapped type behaves is a little similar to how the readonly property on classes behaves, however much more powerful to transform entire data structures at once.

Let’s assume that we have a User which can be created when signing up to a website, creating an account:

interface User {
  id: string;
  name: string;
  email: string;
}

Once this user has been created, we do not want to modify any of those properties.

One option may be to use the readonly modifier on each property:

interface ReadonlyUser {
  readonly id: number;
  readonly name: string;
  readonly email: string;
}

Certainly this works, but can we do better? Yes, of course!

Adding readonly to every single property is an overhead, but also let’s say we want to now change the initial User interface, we’d have to also ensure that the ReadonlyUser was changed as well. This opens up room for errors and mismatched type definitions.

So, what’s the better way? Mapped types!

A mapped type liked Readonly will essentially “map” over our interface properties and change them. The Readonly mapped type is exactly what we’re looking for to achieve automatic readonly properties:

interface User {
  id: string;
  name: string;
  email: string;
}

Once this user has been created, we do not want to modify any of those properties.

One option may be to use the readonly modifier on each property:

// { readonly id: string; readonly name: string; readonly email: string; }
type ReadonlyUser = Readonly<User>;

Simple as that. Mapped types are an efficient way to reduce the code you write, whilst helping you to create even more type-safe code.

As a real-world example, I’d love to show you Object.freeze (which is one of my favourite methods ever).

Here’s the TypeScript signature for Object.freeze:

freeze<T>(o: T): Readonly<T>;

Recognise the Readonly mapped type? This is super because TypeScript constructs these mapped types on-the-fly for us. So our data before it’s passed into Object.freeze would be mutable and unfrozen, and as soon as we get it back from Object.freeze it’ll automatically be marked as readonly for every property.

Hiding mapped types away like this inside function calls is also fantastic, as it uses the generic type to infer our type down into the function and back out as frozen.

🏆 Check out my series of TypeScript Courses where you’ll learn TypeScript in-depth with real-world scenarios and examples to supercharge your JavaScript development.

So you’ve learned how to use the Readonly mapped type in TypeScript, but also more importantly how to use it with generic types in our Object.freeze example to let your data flow in and out and be mapped efficiently.

It’s also nice to not have to keep creating seemingly duplicated interface logic that simply marks things as readonly when a mapped type is fully sufficient.

But, if you need to just modify some properties on a class or interface, you’re probably best to go with a readonly property.

Happy mapping!

Learn TypeScript the right way.

The most complete guide to learning TypeScript ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover