Type subsets with TypeScript Partials
March 2, 2020 ‐ 3 min read
The Partial type is one of the utility types in TypeScript. You can use the Partial type to represent a subsets of the type variable you pass to it.
In an application that communicates with a REST API you ofter find yourself writing interfaces to represent a resource you want to create. If you're about to create a new user your interface might look similar to the one below.
interface User {
firstName: string;
lastName: string;
email: string;
}
If you have all the required properties and pass them in a function that expects a User TypeScript is happy and won't complain.
function createUser(user: User) {
// ...
}
const user: User = {
firstName: "Winston",
lastName: "Tortoise",
email: "w.tortoise@example.com",
};
createUser(user);
But now that you have sir Winston in your database and he decides to change his email address. You can't just pass the update for a single property into a function that expects a parameter of type User. TypeScript won't be happy and will complain.
function updateUser(user: User) {
// ...
}
const newMail = "winston.tortoise@example.com";
updateUser({ email: newMail }); // TypeScript says NO!
So how to solve this. Instead of creating a second interface to represent a specific user update you could give Partial a try. With the Partial utility type you create a new type from an already existing one but makes all the properties optional. To make this a bit more visual, see the snipper below of how the Partial type is defined in TypeScript.
/**
* Make all properties in T optional
*/
type Partial<T> = {
[P in keyof T]?: T[P];
};
So to make TypeScript happy we use the Partial utility type with User
as its generic. By doing this the updateUser
will only accept an object with properties in the User
type. Take note that all the properties are made optional, so even an empty object will be fine in this case.
function updateUser(user: Partial<User>) {
// ...
}
const newMail = "winston.tortoise@example.com";
updateUser({ email: newMail }); // TypeScript is happy
Require one property in partial
Having all the fields optional is in some cases not what you want. For example, sometimes all the fields can be optional expect for an unique identifier you need to identify a specific user. This might not not be the most elegant solution but you could solve this by combining a partial with the Pick utility type. The Pick
type requires a subset of properties in a type. See the snippet below of how the Pick
type is implemented in TypeScript.
/**
* From T, pick a set of properties whose keys are in the union K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
In the example below shows how to combine Pick with Partial to make all properties of User
optional except for the email
property.
function updateUser(user: Pick<Partial<User>, "email">) {
// ...
}
// TypeScript says NO :(
updateUser({ firstName: "Hannah" });
// TypeScript says Yes! :)
updateUser({ firstName: "Hannah", email: "hannah@example.com" });
List of partials
Partials can be used with as a list too. By adding a []
after the Partial type TypeScript will expect an array of partials. The items in the array of partials don't need to have the same properties. So TypeScript is 100% fine with the example below.
const users: Partial<User>[] = [
{ firstName: "John" }, // First user
{ lastName: "James" }, // Second user
];