Readonly<Type> Utility Types in TypeScript With Examples
What is Readonly<Type>
Readonly<Type>
in TypeScript is a utility type that makes all properties of a
given type "Type" read-only. This means once you assign values to the properties
of an object with this type, you cannot change them later. It is a way to ensure
that an object remains constant and cannot be accidentally modified after it is
created.
How Readonly<Type>
Works
The syntax for Readonly<Type>
in TypeScript is quite simple. Here's a
breakdown of the syntax:
Readonly
: This is the TypeScript utility type that is used to create a new type with all properties as read-only.<Type>
: This is a placeholder for the actual type you want to make read-only. You need to replace "Type" with the name of the type you're working with.
Let's say you have an interface called Person:
interface Person {
name: string;
age: number;
}
Now you want to create a read-only version of this interface. You can use
the Readonly<Type>
utility like this:
type ReadonlyPerson = Readonly<Person>;
In this example, Readonly<Person>
creates a new type called ReadonlyPerson
with the same properties as Person
, but all properties are now read-only. This
means you can't change the values of name and age once they are assigned for
objects of type ReadonlyPerson
.
Time To Transition From JavaScript To TypeScript
Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.
SEE COURSE DETAILSLet's create a person
object and then create a readonlyPerson
object
to demonstrate that the values cannot be changed. Here's an example:
const person: Person = {
name: "John",
age: 30,
};
const readonlyPerson: ReadonlyPerson = {
name: "Jane",
age: 28,
};
At this point, you can modify the properties of the person
object without any
issues, because it is of type Person
:
person.name = "John Doe";
person.age = 31;
However, if you try to modify the properties of the readonlyPerson
object,
TypeScript will throw an error because its properties are read-only:
readonlyPerson.name = "Jane Doe";
// Error: Cannot assign to 'name' because it is a read-only property.
readonlyPerson.age = 29;
// Error: Cannot assign to 'age' because it is a read-only property.
As you can see, TypeScript prevents you from changing the values of
the readonlyPerson
object because its type is ReadonlyPerson
, which was
created using the Readonly<Type>
utility.
When to Use Readonly<Type>
Let's consider an example of a simple task management application. In this application, you have a list of tasks, and each task has a title, description, and status (completed or not completed).
Here's a possible use case for Readonly<Type>
in this application:
- You have a function that fetches the list of tasks from an API.
- You want to make sure that once the tasks are fetched and stored in the application, they cannot be accidentally modified, ensuring data consistency.
First, let's define a Task
interface:
interface Task {
id: number;
title: string;
description: string;
completed: boolean;
}
Now create a ReadonlyTask
type using the Readonly<Type>
utility:
type ReadonlyTask = Readonly<Task>;
Let's say you have a function called fetchTasks
that fetches tasks from an API
and returns an array of ReadonlyTask
:
// Function to fetch tasks (dummy implementation)
async function fetchTasksFromAPI(): Promise<Task[]> {
// Create an array of dummy tasks
const tasks: Task[] = [
{
id: 1,
title: "Task 1",
description: "Description for Task 1",
completed: false,
},
{
id: 2,
title: "Task 2",
description: "Description for Task 2",
completed: true,
},
{
id: 3,
title: "Task 3",
description: "Description for Task 3",
completed: false,
},
];
// Mimic an asynchronous operation by returning a
// Promise that resolves with the dummy tasks
return new Promise((resolve) => {
setTimeout(() => {
resolve(tasks);
}, 1000); // Simulate a 1-second delay
});
}
async function fetchTasks(): Promise<ReadonlyTask[]> {
// Fetch tasks from an API and
// store them in a variable called tasks
const tasks: Task[] = await fetchTasksFromAPI();
// Convert tasks to readonly tasks
const readonlyTasks: ReadonlyTask[] = tasks.map((task) => {
return {
id: task.id,
title: task.title,
description: task.description,
completed: task.completed,
};
});
return readonlyTasks;
}
Now, when you fetch tasks using the fetchTasks
function, you'll get an array
of
ReadonlyTask
objects. This ensures that the tasks fetched from the API cannot
be
accidentally modified while working with them in your application. We can
check this this as well by calling the function and tryiong to modify one of
the tasks that is returned from the fetchTasks
function:
const tasks = await fetchTasks();
tasks[0].title = "New Title";
// Error: Cannot assign to 'title' because it is a read-only property.
In this example, using Readonly<Type>
helps maintain data consistency and
prevents unintended modifications of the task objects throughout the
application.
What Can You Do Next 🙏😊
If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for software developers.