Утилітарні типи (Utility Types) — це вбудовані типи TypeScript, які дозволяють змінювати або маніпулювати існуючими типами. Вони допомагають зробити код більш гнучким і зрозумілим.
Сьогодні ми розберемо абсотно всі такі типи, включно з непопулярними, щоб ви не лякалися, коли бачили їх в коді якогось сніча. Деякі з них ми вже обговорювали в попередньому уроці, але я все одно перечислю їх всі.
Partial<T>
Робить всі властивості типу T необов’язковими
type User = {
name: string;
age: number;
};
const updateUser = (user: Partial<User>) => {
// можна передавати частковий об'єкт
console.log(user);
};
updateUser({ name: "Andrii" });
Required<T>
Робить всі властивості обов’язковими
type User = {
name?: string;
age?: number;
};
const createUser = (user: Required<User>) => {
// тепер name та age — обов’язкові
};
createUser({ name: "Olena", age: 25 });
Readonly<T>
Робить всі властивості тільки для читання
type User = {
name: string;
};
const user: Readonly<User> = {
name: "Oleh"
};
// user.name = "Ivan"; // помилка: неможливо змінити readonly властивість
Pick<T, K>
Обирає лише вказані ключі з типу T
type User = {
id: number;
name: string;
email: string;
};
type UserPreview = Pick<User, "id" | "name">;
Omit<T, K>
Видаляє вказані ключі з типу T
type User = {
id: number;
name: string;
email: string;
};
type WithoutEmail = Omit<User, "email">;
Record<K, T>
Створює об’єкт з ключами K та значеннями типу T
type Roles = "admin" | "user" | "guest";
type Permissions = "read" | "write" | "delete";
const rolePermissions: Record<Roles, Permissions[]> = {
admin: ["read", "write", "delete"],
user: ["read", "write"],
guest: ["read"]
};
Exclude<T, U>
Видаляє з T всі типи, які є в U
type Status = "pending" | "approved" | "rejected";
type FinalStatus = Exclude<Status, "pending">;
// FinalStatus: "approved" | "rejected"
Extract<T, U>
Залишає в T лише ті типи, які є в U
type A = "a" | "b" | "c";
type B = "a" | "d";
type Common = Extract<A, B>; // "a"
ReturnType<T>
Отримує тип, який повертає функція T
function getUser() {
return {
name: "Sofiia",
age: 30
};
}
type User = ReturnType<typeof getUser>;
NonNullable<T>
Видаляє null та undefined з типу T
type MaybeName = string | null | undefined;
type CleanName = NonNullable<MaybeName>; // string
InstanceType<T>
Отримує тип екземпляру класу
class User {
name = "Admin";
login() {}
}
type UserInstance = InstanceType<typeof User>;
// UserInstance: User
const user: UserInstance = new User();
ThisType<T>
Дає контроль над контекстом this (використовується з об’єктами)
Працює лише в поєднанні з noImplicitThis: true у tsconfig.
type ObjectWithHelpers = {
x: number;
y: number;
helpers: {
move(dx: number, dy: number): void;
} & ThisType<{ x: number; y: number }>; // Тип для this у helpers
};
const point: ObjectWithHelpers = {
x: 0,
y: 0,
helpers: {
move(dx, dy) {
this.x += dx;
this.y += dy;
},
},
};
point.helpers.move(5, 7);
console.log(point.x, point.y); // 5 7
Awaited<T>
Отримує тип, який повертається з Promise<T> або async функції
type MaybePromise = Promise<string>;
type Result = Awaited<MaybePromise>; // string
async function fetchData() {
return { id: 1, name: "Product" };
}
type Data = Awaited<ReturnType<typeof fetchData>>;
// Data: { id: number, name: string }
ConstructorParameters<T>
Працює як з класами, так і з конструкторами - отримує параметри конструктора класу.
class Person {
constructor(public name: string, public age: number) {}
}
type PersonArgs = ConstructorParameters<typeof Person>;
// PersonArgs: [name: string, age: number]
const person = new Person(...["Anna", 22] satisfies PersonArgs);
AbstractConstructor<T>
Окремо хотів би ще показати як працювати з абстрактними класами на прикладі AbstractConstructor<T>, але його нема в стандартному пакеті утилітарних типів, тобто вам треба його створювати вручну, але він дуже користний для типізації абстрактних класів.
type AbstractConstructor<T> = abstract new (...args: any[]) => T;
abstract class Animal {
abstract speak(): void;
}
class Dog extends Animal {
speak() {
console.log("Bark");
}
}
function createInstance<C extends AbstractConstructor<Animal>>(ctor: C) {
return new ctor();
}
const dog = createInstance(Dog); // ✅ OK