Пошук уроків, статей та іншого контенту
Створюйте власні іменовані типи за допомогою type alias і повторно використовуйте їх у коді.
Type alias — це власне ім’я для типу, яке створюється за допомогою ключового слова type.
type UserId = string;
const userId: UserId = "user-42";Тепер UserId можна використовувати в різних місцях коду так само, як вбудований тип string.
Псевдонім типу не створює нового значення під час виконання програми. Він використовується лише TypeScript для перевірки типів.
Type alias особливо зручний для опису структури об'єктів:
type User = {
id: string;
name: string;
email: string;
isActive: boolean;
};
const user: User = {
id: "user-1",
name: "Олена",
email: "olena@example.com",
isActive: true,
};Той самий тип можна повторно використовувати для параметрів функцій, значень, які повертає функція, і масивів:
type User = {
id: string;
name: string;
email: string;
isActive: boolean;
};
function printUser(user: User): string {
return `${user.name} <${user.email}>`;
}
function findActiveUsers(users: User[]): User[] {
return users.filter((user) => user.isActive);
}
const users: User[] = [
{
id: "user-1",
name: "Олена",
email: "olena@example.com",
isActive: true,
},
{
id: "user-2",
name: "Андрій",
email: "andrii@example.com",
isActive: false,
},
];
console.log(printUser(users[0]));
console.log(findActiveUsers(users));Якщо спробувати створити об'єкт без обов'язкової властивості або з неправильним типом, TypeScript повідомить про помилку:
type Product = {
id: number;
title: string;
price: number;
};
const product: Product = {
id: 1,
title: "Клавіатура",
// Помилка: price має бути вказаною і мати тип number
};У псевдонімах об'єктних типів можна використовувати такі самі модифікатори властивостей, як і в інших типах TypeScript.
Знак ? робить властивість необов'язковою:
type Profile = {
username: string;
bio?: string;
};
const firstProfile: Profile = {
username: "coder",
};
const secondProfile: Profile = {
username: "typescript_dev",
bio: "Розробляю вебзастосунки",
};Модифікатор readonly забороняє змінювати властивість після створення об'єкта:
type Configuration = {
readonly environment: "development" | "production";
apiUrl: string;
};
const configuration: Configuration = {
environment: "development",
apiUrl: "https://example.com",
};
// Помилка: властивість доступна лише для читання
// configuration.environment = "production";
configuration.apiUrl = "https://api.example.com";readonly перевіряється TypeScript під час компіляції. Він не робить об'єкт автоматично незмінним під час виконання JavaScript.
Type alias може описувати не лише об'єкт, а й об'єднання типів (union type).
type Status = "pending" | "success" | "error";
let requestStatus: Status = "pending";
requestStatus = "success";
// requestStatus = "cancelled"; // Помилка: такого значення немає в StatusТакий підхід називають об'єднанням літеральних типів. Він корисний, коли змінна може містити лише один із заздалегідь визначених варіантів.
Об'єднання можна використовувати для опису різних форм даних:
type ApiResponse =
| {
status: "success";
data: string[];
}
| {
status: "error";
message: string;
};
function handleResponse(response: ApiResponse): void {
if (response.status === "success") {
console.log("Отримано елементів:", response.data.length);
} else {
console.error("Помилка:", response.message);
}
}
handleResponse({
status: "success",
data: ["TypeScript", "JavaScript"],
});
handleResponse({
status: "error",
message: "Сервер недоступний",
});TypeScript розуміє, які властивості доступні всередині кожної гілки if. Перевірка response.status звужує тип до відповідного варіанта.
За допомогою оператора & можна поєднати кілька типів у один. Такий тип називається перетином (intersection type).
type Timestamps = {
createdAt: Date;
updatedAt: Date;
};
type Identifiable = {
id: string;
};
type Document = Timestamps & Identifiable & {
title: string;
};
const document: Document = {
id: "doc-1",
title: "Посібник TypeScript",
createdAt: new Date(),
updatedAt: new Date(),
};Тип Document містить усі властивості з Timestamps, Identifiable і власну властивість title.
Перетини зручні, коли кілька сутностей мають спільні частини:
type WithId = {
id: string;
};
type Article = WithId & {
title: string;
content: string;
};
type Video = WithId & {
title: string;
durationInSeconds: number;
};Type alias може описувати сигнатуру функції:
type Formatter = (value: number) => string;
const formatPrice: Formatter = (value) => {
return `${value.toFixed(2)} грн`;
};
const formatPercent: Formatter = (value) => {
return `${value}%`;
};
console.log(formatPrice(1250));
console.log(formatPercent(15));Такий підхід допомагає гарантувати, що всі функції певного призначення приймають однакові аргументи й повертають однаковий тип.
Можна також створити окремі псевдоніми для параметрів і результату:
type User = {
id: string;
name: string;
};
type UserFactory = (name: string) => User;
const createUser: UserFactory = (name) => {
return {
id: crypto.randomUUID(),
name,
};
};
console.log(createUser("Марія"));Псевдонім робить складний тип масиву зрозумілішим:
type Score = number;
type Scores = Score[];
const scores: Scores = [10, 8, 9];Для масивів об'єктів:
type Task = {
id: number;
title: string;
completed: boolean;
};
type TaskList = Task[];
const tasks: TaskList = [
{
id: 1,
title: "Вивчити type alias",
completed: true,
},
{
id: 2,
title: "Написати приклад",
completed: false,
},
];Псевдонім може описувати кортеж — масив фіксованої довжини з відомими типами елементів:
type Coordinates = [number, number];
const point: Coordinates = [50.4501, 30.5234];
// Помилка: у кортежі мають бути два числа
// const invalidPoint: Coordinates = [50.4501];Псевдоніми можна будувати на основі інших псевдонімів. Це дає змогу описувати модель невеликими логічними частинами:
type Id = string;
type Address = {
city: string;
street: string;
};
type Customer = {
id: Id;
name: string;
address: Address;
};
const customer: Customer = {
id: "customer-1",
name: "Ірина",
address: {
city: "Львів",
street: "вулиця Шевченка",
},
};Якщо одна частина моделі зміниться, її можна оновити в одному місці.
Псевдоніми також можна комбінувати з вбудованими операторами типів:
type Product = {
id: string;
name: string;
price: number;
};
type ProductPreview = Pick<Product, "id" | "name">;
type ProductUpdate = Partial<Product>;
const preview: ProductPreview = {
id: "product-1",
name: "Монітор",
};
const update: ProductUpdate = {
price: 8999,
};Pick створює тип лише з вибраних властивостей, а Partial робить усі властивості необов'язковими.
І type, і interface можуть описувати форму об'єкта:
type UserByType = {
id: string;
name: string;
};
interface UserByInterface {
id: string;
name: string;
}Для простих об'єктних моделей обидва варіанти можуть бути доречними. Водночас type має ширші можливості для створення:
об'єднань типів;
перетинів;
кортежів;
псевдонімів примітивних типів;
типів функцій.
Наприклад, об'єднання можна безпосередньо описати через type:
type Result = string | number;Вибір між type та interface часто залежить від стилю проєкту. Якщо потрібно створити саме псевдонім для довільного типу або комбінувати типи за допомогою | чи &, використовуйте type.
Type alias є лише іншим ім'ям для вже наявного типу. Він не створює окремий несумісний тип.
type UserId = string;
type OrderId = string;
const userId: UserId = "user-1";
const orderId: OrderId = "order-1";
const anotherOrderId: OrderId = userId;Останнє присвоєння дозволене, оскільки і UserId, і OrderId фактично є string.
Якщо потрібно, щоб два значення не можна було випадково змішати, одного type alias недостатньо. Для цього застосовують інші підходи, наприклад брендування типів. У більшості звичайних моделей даних це не потрібно.
У наступному прикладі кілька псевдонімів описують стан завантаження даних і використовуються разом:
type User = {
id: string;
name: string;
};
type LoadingState = {
status: "loading";
};
type SuccessState = {
status: "success";
users: User[];
};
type ErrorState = {
status: "error";
message: string;
};
type UsersState = LoadingState | SuccessState | ErrorState;
function renderUsersState(state: UsersState): string {
switch (state.status) {
case "loading":
return "Завантаження...";
case "success":
return `Користувачів: ${state.users.length}`;
case "error":
return `Помилка: ${state.message}`;
}
}
const states: UsersState[] = [
{ status: "loading" },
{
status: "success",
users: [
{ id: "user-1", name: "Олена" },
{ id: "user-2", name: "Андрій" },
],
},
{
status: "error",
message: "Не вдалося отримати дані",
},
];
for (const state of states) {
console.log(renderUsersState(state));
}Дискримінант status дає змогу TypeScript розрізняти варіанти UsersState і безпечно звертатися до їхніх властивостей.
= замість =Псевдонім типу оголошують за допомогою знака =:
type User = {
name: string;
};Правильна форма — type Name = Type. Не потрібно використовувати == або пропускати знак =.
Якщо одна й та сама форма об'єкта повторюється в кількох місцях, краще винести її в псевдонім:
type Product = {
id: string;
name: string;
price: number;
};
function getProduct(): Product {
return {
id: "product-1",
name: "Ноутбук",
price: 42000,
};
}
function printProduct(product: Product): void {
console.log(product.name, product.price);
}Це зменшує дублювання і спрощує зміни.
Не варто замінювати обмежений набір значень типом string, якщо набір відомий заздалегідь:
type Theme = "light" | "dark";
function setTheme(theme: Theme): void {
console.log(`Обрана тема: ${theme}`);
}
setTheme("dark");
// setTheme("blue"); // ПомилкаЗамість string TypeScript перевірятиме лише дозволені варіанти.
| та &| означає «один із типів»:
type Id = string | number;& означає «всі типи одночасно»:
type Entity = {
id: string;
} & {
createdAt: Date;
};Для перетину об'єкт має містити властивості обох частин.
Type alias створюється синтаксисом type Name = Type.
Псевдоніми дають імена об'єктам, примітивам, масивам, кортежам і функціям.
Один псевдонім можна повторно використовувати в багатьох місцях програми.
| створює об'єднання типів, а & — їхній перетин.
Літеральні об'єднання обмежують значення заздалегідь визначеним набором.
Псевдоніми можна комбінувати між собою та з утилітарними типами.
Type alias існує лише на етапі перевірки TypeScript і не створює нового значення під час виконання.