Что такое утилитные типы (Partial, Pick, Omit, Readonly) и где они применяются?

TypeScript предоставляет ряд утилитных типов, которые позволяют изменять или переопределять уже существующие типы без их полного дублирования. Это делает код более гибким, сокращает количество повторяющихся объявлений и помогает точнее описывать различные сценарии использования объектов. Наиболее часто применяемыми являются Partial, Pick, Omit и Readonly.

Partial

Partial<T> делает все свойства переданного типа T необязательными. Это полезно в ситуациях, когда нужно работать с объектом, который может содержать только часть свойств исходного интерфейса.

Пример:

interface User {
name: string;
age: number;
email: string;
}
const updateUser = (id: number, data: Partial&lt;User&gt;) => {
// обновляем только те поля, которые переданы
};
updateUser(1, { age: 30 });

Здесь функция updateUser принимает объект, который может содержать любое подмножество свойств User.

Pick

Pick<T, K> создаёт новый тип, выбирая только указанные свойства K из типа T. Это полезно, когда требуется ограничить доступ к определённым полям.

Пример:

interface User {
name: string;
age: number;
email: string;
}
type UserPreview = Pick&lt;User, "name" | "email"&gt;;
const user: UserPreview = {
name: "Alice",
email: "alice@example.com"
};

Таким образом, UserPreview содержит только имя и email, исключая другие поля.

Omit

Omit<T, K> работает противоположно Pick: он создаёт тип, исключая указанные свойства K из типа T. Это полезно, когда почти все свойства нужны, кроме нескольких.

Пример:

interface User {
name: string;
age: number;
email: string;
password: string;
}
type PublicUser = Omit&lt;User, "password"&gt;;
const safeUser: PublicUser = {
name: "Alice",
age: 25,
email: "alice@example.com"
};

Здесь мы исключили поле password, чтобы не хранить его в публичных структурах данных.

Readonly

Readonly<T> делает все свойства переданного типа доступными только для чтения. Это полезно в тех случаях, когда нужно предотвратить случайное изменение объекта после его создания.

Пример:

interface User {
name: string;
age: number;
}
const user: Readonly&lt;User&gt; = {
name: "Alice",
age: 25
};
user.age = 26; // Ошибка: свойство только для чтения

Такой подход применяется, когда объект должен оставаться неизменным после инициализации, что снижает вероятность ошибок.

Практическое применение

Эти утилитные типы широко используются при работе с DTO (Data Transfer Objects), API-ответами, формами и конфигурациями.

  • Partial помогает при обновлении объектов частичными данными.

  • Pick удобен, если нужно ограничить набор полей для отображения или передачи.

  • Omit подходит для исключения чувствительных данных перед отправкой или логированием.

  • Readonly используется для защиты состояния от модификаций.

Таким образом, утилитные типы позволяют гибко управлять структурой данных, избегая дублирования кода и повышая надежность приложения.