Typescript allows developers to use static type-checking in JavaScript. It also adds the ability to create new custom types as necessary during development. Asides from allowing the creation of new types, Typescript also allows for the transformation of existing types.
Typescript provides some globally available utility types. These utility types allows the developer to carry out these common type transformations.
In this article we look at some commonly used Utility types and when we can use them in our code.
The utility type Partial creates a new type where all the properties of the input type T
are set to optional.
interface Point {
x: number;
y: number;
z?: number;
}
type PointPartial = Partial<Point>
// {
// x?: number;
// y?: number;
// z?: number;
// }
It can be used to type the parameter of a function that is used to update the properties of an object as can be seen in the example below.
interface User {
firstName: string;
lastName: string;
age: number;
}
const updateUser = (user: User, updatedFields: Partial<User>) => ({
...user,
...updatedFields,
});
const user1: User = {
firstName: "Anderson",
lastName: "Osayerie",
age: 27,
};
const user2 = updateUser(user1, { age: 28 });
console.log(user2); // { name: "Anderson", surname: "Osayerie", age: 28 }
The utility type Required creates a new type where all the properties of the input type T
are set to required. It is the opposite of Partial.
interface Point {
x: number;
y: number;
z?: number;
}
type PointRequired = Required<Point>;
// {
// x: number;
// y: number;
// z: number;
// }
Below is an example of where we can use the Required type. The Todo
interface with the ID property being optional can be used when creating the todo because we do not know the ID at that point. But when we want to update the todo, we have to make sure the ID is set.
interface Todo {
id?: number;
title: string;
description: string;
}
const createTodo = (todo: Todo) => {
const newTodo = db.create(todo);
return newTodo;
};
const updateTodo = (todo: Required<Todo>) => {
const updatedTodo = db.update(todo);
return updatedTodo;
};
createTodo({
title: "Write article",
description: "Choose topic",
});
updateTodo({
id: 3,
title: "Write article",
description: "Topic choosen",
});
The utility type Readonly creates a new type where all the properties of the input type T
are set to readonly. The properties of the new type cannot be reassigned.
interface Point {
x: number;
y: number;
z?: number;
}
type PointReadonly = Readonly<Point>;
// {
// readonly x: number;
// readonly y: number;
// readonly z?: number;
// }
The Readonly utility is useful for showing assignment expressions that would fail at runtime. This occurs when trying to reassign the properties of a frozen object.
interface User {
firstName: string;
lastName: string;
age: number;
}
const freeze = <T>(obj: T): Readonly<T> => Object.freeze(obj);
const user: User = {
firstName: "Anderson",
lastName: "Osayerie",
age: 27,
};
const readonlyUser = freeze(user);
// Cannot assign to 'age' because it is a read-only property
readonlyUser.age = 28;
In this article we have considered three built-in utility types provided by Typescript and how we can use them in our code.