Gernar
TypeScript

Что такое Utility Types в TypeScript

Разбор вопроса «Что такое Utility Types в TypeScript» для Frontend Developer: что проверяет интервьюер, ключевые тезисы, практические примеры и частые ошибки.

Вопрос

Что такое Utility Types в TypeScript

Профессия

Frontend Developer

Что хочет услышать интервьюер

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

Ключевые тезисы

  • Utility Types — это встроенные в TypeScript типы, которые упрощают работу с типами, предоставляя готовые шаблоны для их преобразования.
  • Они позволяют манипулировать существующими типами, например, делать их свойства опциональными (Partial), только для чтения (Readonly) или выбирать только определённые свойства (Pick).
  • Примеры Utility Types: Partial<T>, Required<T>, Readonly<T>, Record<K, T>, Pick<T, K>, Omit<T, K>, Exclude<T, U>, Extract<T, U>, NonNullable<T>.
  • Эти типы часто используются для уменьшения дублирования кода и упрощения работы с сложными типами.

Подробный ответ

Utility Types в TypeScript — это набор предопределённых обобщённых типов, которые позволяют преобразовывать существующие типы для решения распространённых задач. Они встроены в TypeScript и значительно упрощают работу с типами, уменьшая количество рутинного кода. Например, вместо того чтобы вручную создавать интерфейс с необязательными полями, можно использовать Partial<T>, который автоматически сделает все свойства типа T необязательными.

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

Utility Types также помогают в комбинировании и манипулировании типами. Например, Record<K, T> создаёт тип, где ключи имеют тип K, а значения — тип T. Это удобно для создания словарей или объектов с динамическими ключами. А Exclude<T, U> и Extract<T, U> позволяют фильтровать типы, что полезно при работе с объединениями типов (union types).

Практические примеры

Пример 1

Пример использования Partial<T>:

interface User {
  id: number;
  name: string;
  email: string;
}

function updateUser(user: User, fieldsToUpdate: Partial<User>) {
  return { ...user, ...fieldsToUpdate };
}

const user: User = { id: 1, name: 'Alice', email: 'alice@example.com' };
const updatedUser = updateUser(user, { name: 'Alice Smith' }); // Можно обновить только имя

Пример 2

Пример использования Pick&lt;T, K&gt; и Omit&lt;T, K&gt;:

interface Product {
  id: number;
  name: string;
  price: number;
  category: string;
}

type ProductPreview = Pick<Product, 'id' | 'name'>; // { id: number; name: string }
type ProductWithoutCategory = Omit<Product, 'category'>; // { id: number; name: string; price: number }

Пример 3

Пример использования Record&lt;K, T&gt;:

type PageViews = Record<string, number>; // { [key: string]: number }
const views: PageViews = {
  home: 1000,
  about: 500,
  contact: 200
};

Частые ошибки

  • Путаница между Pick&lt;T, K&gt; и Omit&lt;T, K&gt;. Pick выбирает указанные свойства, а Omit исключает их.
  • Использование Partial&lt;T&gt; для всех полей, когда некоторые из них должны остаться обязательными. В таких случаях лучше комбинировать Utility Types.
  • Непонимание разницы между Exclude&lt;T, U&gt; (исключает из T всё, что можно присвоить U) и Extract&lt;T, U&gt; (оставляет только то, что можно присвоить U).

Связанные темы

  • Generics в TypeScript
  • Union Types и Intersection Types
  • Type Inference и Type Guards
  • Работа с интерфейсами и типами в TypeScript

Follow-up вопросы

Можешь объяснить, как работает Partial&lt;T&gt; и в каких случаях его стоит использовать?

Уровень: basic

Partial&lt;T&gt; делает все свойства типа T опциональными. Это полезно, когда нужно создать объект, который может быть заполнен постепенно, например, при инициализации состояния или обновлении данных.

Как работает Pick&lt;T, K&gt; и чем он отличается от Omit&lt;T, K&gt;?

Уровень: intermediate

Pick&lt;T, K&gt; создаёт новый тип, включающий только указанные свойства K из типа T. Omit&lt;T, K&gt;, наоборот, исключает указанные свойства K из типа T. Например, Pick используется для выделения нужных полей, а Omit — для их удаления.

В чём разница между Exclude&lt;T, U&gt; и Extract&lt;T, U&gt;?

Уровень: intermediate

Exclude&lt;T, U&gt; исключает из типа T все типы, которые совпадают с U. Extract&lt;T, U&gt;, наоборот, оставляет только те типы из T, которые совпадают с U. Например, Exclude используется для фильтрации типов, а Extract — для их извлечения.

Как работает Record&lt;K, T&gt; и где его можно применить?

Уровень: advanced

Record&lt;K, T&gt; создаёт тип, где ключи имеют тип K, а значения — тип T. Это полезно для создания объектов с динамическими ключами, например, словарей или маппингов.

Какой Utility Type используется для создания неизменяемых (read-only) типов?

Уровень: basic

Readonly&lt;T&gt; делает все свойства типа T доступными только для чтения. Это полезно для предотвращения случайного изменения данных, например, в объектах состояния.

Содержание