TypeScript Partial, Required, and Readonly
TypeScript provides built-in utility types to transform the properties of an interface or type alias. Three of the most fundamental utilities deal with property modifiers: optionality (?) and immutability (readonly).
1. Partial<Type>
Partial<Type> constructs a type with all properties of Type set to optional. This is useful when you need to update an object but might only have a subset of the fields.
Example
interface User {
id: number;
name: string;
email: string;
}
// All fields become optional: { id?: number; name?: string; email?: string; }
type PartialUser = Partial<User>;
function updateUser(user: User, fieldsToUpdate: Partial<User>) {
return { ...user, ...fieldsToUpdate };
}
const user = { id: 1, name: "Alice", email: "alice@example.com" };
updateUser(user, { name: "Bob" }); // OK: We didn't provide 'email' or 'id'
2. Required<Type>
Required<Type> is the opposite of Partial. It constructs a type consisting of all properties of Type set to required. It removes the ? modifier from all properties.
Example
interface Config {
host?: string;
port?: number;
timeout?: number;
}
// All fields become required: { host: string; port: number; timeout: number; }
type CompleteConfig = Required<Config>;
const defaultConfig: CompleteConfig = {
host: "localhost",
port: 8080,
timeout: 5000
};
// Error: Property 'timeout' is missing in type...
// const badConfig: CompleteConfig = {
// host: "localhost",
// port: 3000
// };
3. Readonly<Type>
Readonly<Type> constructs a type with all properties of Type set to readonly. This means the properties of the constructed type cannot be reassigned.
Example
interface Todo {
title: string;
}
const todo: Readonly<Todo> = {
title: "Delete inactive users"
};
// todo.title = "Hello"; // Error: Cannot assign to 'title' because it is a read-only property.
Note: This is shallow immutability. If a property is an object, the properties of that nested object are still mutable unless recursively frozen.
4. How they work (Under the hood)
These types are implemented using Mapped Types.
// Partial
type Partial<T> = {
[P in keyof T]?: T[P];
};
// Required
type Required<T> = {
[P in keyof T]-?: T[P]; // The -? removes the optional modifier
};
// Readonly
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
programming/javascript/typescript/typescript programming/javascript/typescript/utility-types