Утилитарные типы в 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"
Пример использования
-
Использование в аргументах функции
Вы можете использовать
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
-
Улучшение ограничений типов
Используя
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-канал.