Утилитарные типы в TypeScript

Утилитарные типы в TypeScript

В этой статье объясняются утилитарные типы в TypeScript.

YouTube Video

Утилитарные типы в TypeScript

Утилитарные типы TypeScript - это удобные инструменты для создания новых типов на основе существующих типов. Это позволяет создавать более гибкие определения типов и увеличивает переиспользование кода. Здесь мы подробно объясним часто используемые утилитарные типы и обсудим, как использовать каждый из них с примерами кода.

Partial<T>

Partial<T> делает все свойства типа объекта необязательными (позволяя использовать undefined). Это полезно, когда вы хотите использовать только некоторые из свойств исходного типа.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5}
 6
 7function updateUser(user: Partial<User>) {
 8  console.log(user);
 9}
10
11updateUser({ name: "Alice" }); // Updates only 'name'

Объяснение:

В приведенном выше примере использование Partial<User> делает все свойства типа User необязательными. Таким образом, в функции updateUser вы можете передать только подмножество свойств.

Required<T>

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

 1interface User {
 2  id: number;
 3  name?: string;
 4  age?: number;
 5}
 6
 7function createUser(user: Required<User>) {
 8  console.log(user);
 9}
10
11// createUser({ id: 1 }); // Error: 'name' and 'age' are required
12createUser({ id: 1, name: "Alice", age: 25 });

Объяснение:

Используя Required<User>, такие свойства, как name и age, считаются обязательными.

Readonly<T>

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

 1interface User {
 2  id: number;
 3  name: string;
 4}
 5
 6const user: Readonly<User> = {
 7  id: 1,
 8  name: "Alice"
 9};
10
11// user.id = 2; // Error: 'id' is read-only
12console.log(user);

Объяснение:

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

Record<K, T>

Record<K, T> создает тип карты со специфицированными типами ключей и значений. K - это тип ключей (например, string или number), а T - это тип значений.

 1type Roles = "admin" | "user" | "guest";
 2interface Permissions {
 3  read: boolean;
 4  write: boolean;
 5}
 6
 7const rolePermissions: Record<Roles, Permissions> = {
 8  admin: { read: true, write: true },
 9  user: { read: true, write: false },
10  guest: { read: false, write: false },
11};
12
13console.log(rolePermissions);

Объяснение:

Record<K, T> полезен, когда вы хотите определить пары ключ-значение. В приведенном выше примере разрешения определяются на основе ролей пользователей.

Pick<T, K>

Pick<T, K> извлекает только указанные свойства из типа объекта. Вы можете создать новый тип, извлекая только необходимые свойства.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5}
 6
 7type UserSummary = Pick<User, "id" | "name">;
 8
 9const summary: UserSummary = {
10  id: 1,
11  name: "Alice"
12};
13
14console.log(summary);

Объяснение:

Используя Pick<T, K>, вы можете извлечь определенные свойства из типа объекта и рассматривать их как новый тип. Например, в приведенном выше примере извлекаются только id и name.

Omit<T, K>

Omit<T, K> исключает указанные свойства из типа объекта. Это противоположная операция Pick.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5  email: string;
 6}
 7
 8type UserWithoutEmail = Omit<User, "email">;
 9
10const userWithoutEmail: UserWithoutEmail = {
11  id: 1,
12  name: "Alice",
13  age: 25
14};
15
16console.log(userWithoutEmail);

Объяснение:

Используя Omit<T, K>, вы можете создать новый тип, исключив указанные свойства. В приведённом выше примере свойство email исключено.

Exclude<T, U>

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

1type Status = "active" | "inactive" | "pending";
2type ExcludedStatus = Exclude<Status, "pending">;
3
4const status: ExcludedStatus = "active"; // "pending" is excluded, so it cannot be chosen
5console.log(status);

Объяснение:

С помощью Exclude<T, U> вы можете удалить ненужные типы из объединённого типа. В приведённом выше примере, поскольку "pending" исключён, можно выбрать только "active" или "inactive".

Extract<T, U>

Extract<T, U> извлекает части, соответствующие типу U внутри объединённого типа T. Это полезно, когда нужно извлечь только определённый тип.

1type Status = "active" | "inactive" | "pending";
2type ActiveStatus = Extract<Status, "active" | "pending">;
3
4const status: ActiveStatus = "active"; // "inactive" cannot be chosen
5console.log(status);

Объяснение:

Extract<T, U> выполняет противоположную операцию Exclude. В приведённом выше примере можно выбрать только "active" и "pending".

NonNullable<T>

NonNullable<T> создаёт тип, исключая null и undefined. Это полезно, когда нужно исключить эти значения из необязательных типов.

1type UserName = string | null | undefined;
2type ValidUserName = NonNullable<UserName>;
3
4const name: ValidUserName = "Alice"; // null and undefined cannot be chosen
5console.log(name);

Объяснение:

NonNullable<T> исключает null и undefined из типа, содержащего их. Это полезно, когда вы хотите гарантировать, что значение определённо существует.

Заключение

Утилитарные типы TypeScript — это мощные инструменты для создания более лаконичных и гибких определений типов. Понимание и правильное использование основных утилитарных типов, таких как Partial, Required, Readonly, Record и других, может улучшить переиспользуемость и удобство сопровождения кода. Освоение этих типов позволяет создавать более надёжные и безопасные определения типов, что способствует эффективной разработке.

Оператор keyof в TypeScript

Оператор keyof в TypeScript используется для получения всех имён свойств типа объекта. Используя этот оператор, вы можете получить ключи типа объекта как объединенный тип. Это чрезвычайно полезно для написания кода с безопасными типами.

Основное использование

1interface Person {
2    name: string;
3    age: number;
4    email: string;
5}
6
7// Use keyof to get the property names of Person
8type PersonKeys = keyof Person; // "name" | "age" | "email"

Пример использования

  1. Использование в аргументах функции

    Вы можете использовать keyof для определения функции, которая имеет типы, основанные на конкретных свойствах объекта.

1function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
2    return obj[key];
3}
4
5const person: Person = { name: "Alice", age: 30, email: "alice@example.com" };
6const name = getProperty(person, "name"); // type is string
7const age = getProperty(person, "age");   // type is number
  1. Улучшение ограничений типов

    Используя keyof, вы можете гарантировать, что ключи, передаваемые в функцию, проверяются на этапе компиляции.

1// Passing an invalid property name results in an error
2const invalid = getProperty(person, "invalidKey"); // Error

Резюме

  • Оператор keyof используется для получения всех имен свойств типа объекта.
  • Вы можете получить имена свойств как объединенный тип, что обеспечивает безопасность типов в коде.
  • Используя его в аргументах функции, вы можете ограничить функцию только допустимыми именами свойств.

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

Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.

YouTube Video