Пошук уроків, статей та іншого контенту
Навчитеся застосовувати typeof у позиції типу та Indexed Access Types для вилучення типів властивостей і елементів.
typeof у позиції типуУ JavaScript typeof використовують під час виконання програми, щоб отримати рядок із назвою типу значення:
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"У TypeScript typeof можна використовувати і в позиції типу — праворуч від двокрапки або після ключового слова type. У такому випадку він не виконується під час роботи програми, а вилучає тип змінної або властивості.
const user = {
name: "Олена",
age: 28,
};
type User = typeof user;Тепер User має такий самий тип, як і об’єкт user:
type User = {
name: string;
age: number;
};Це корисно, коли тип можна автоматично отримати з уже створеного значення. Не потрібно дублювати структуру об’єкта вручну.
typeof у JavaScript і TypeScriptОднакове слово typeof має різне призначення залежно від позиції.
typeof у звичайному кодіЦей варіант працює під час виконання програми:
const value = 42;
console.log(typeof value); // "number"Результат typeof value — це рядок.
typeof у типіЦей варіант працює лише на етапі перевірки TypeScript:
const value = 42;
type Value = typeof value;
// type Value = numberValue — це тип number, а не рядок "number".
Операцію typeof у позиції типу можна застосовувати до:
змінних;
констант;
властивостей об’єктів;
функцій;
масивів і кортежів.
Розглянемо об’єкт із налаштуваннями:
const settings = {
theme: "dark",
language: "uk",
notifications: true,
};
type Settings = typeof settings;
const userSettings: Settings = {
theme: "light",
language: "uk",
notifications: false,
};Тип Settings автоматично відповідає структурі settings:
type Settings = {
theme: string;
language: string;
notifications: boolean;
};Якщо змінити структуру settings, TypeScript автоматично врахує ці зміни в Settings.
typeofвилучає тип, а не саме значення. Зміннуsettingsі типSettingsне можна використовувати однаково.
Наприклад:
const settings = {
theme: "dark",
};
type Settings = typeof settings;
const copy: Settings = {
theme: "light",
};copy — це значення, а Settings — лише опис типу.
Щоб отримати тип окремої властивості, після typeof можна використати Indexed Access Type.
Синтаксис:
typeof objectName["propertyName"]Приклад:
const product = {
title: "Ноутбук",
price: 35000,
inStock: true,
};
type Product = typeof product;
type ProductTitle = Product["title"];
type ProductPrice = Product["price"];
type ProductInStock = Product["inStock"];Отримані типи:
// ProductTitle — string
// ProductPrice — number
// ProductInStock — booleanТе саме можна записати без проміжного типу:
type ProductTitle = typeof product["title"];Indexed Access Type читається як «тип властивості title у типі product».
Indexed Access Type дозволяє звернутися до типу за індексом, подібно до звернення до властивості в JavaScript.
У JavaScript:
product["title"];У позиції типу:
type ProductTitle = Product["title"];Цей синтаксис не дістає значення під час виконання. Він лише отримує тип властивості.
type Product = {
title: string;
price: number;
};
type Title = Product["title"]; // string
type Price = Product["price"]; // numberПісля вилучення тип можна використовувати в інших місцях:
type Product = {
title: string;
price: number;
};
type ProductTitle = Product["title"];
function printTitle(title: ProductTitle): void {
console.log(title);
}
printTitle("Механічна клавіатура");Індексом може бути не лише рядковий літерал, а й тип, отриманий із іншої змінної.
const product = {
title: "Монітор",
price: 12000,
inStock: true,
};
type Product = typeof product;
type PropertyName = "title";
type PropertyType = Product[PropertyName];
// stringЗначення PropertyName є типом "title", тому Product[PropertyName] дорівнює Product["title"].
Індекс має бути допустимою властивістю типу. Якщо вказати властивість, якої не існує, TypeScript повідомить про помилку:
type Product = {
title: string;
price: number;
};
// Помилка: властивості "color" немає в типі Product
// type Color = Product["color"];Якщо індексом є об’єднання рядкових літералів, TypeScript поверне об’єднання відповідних типів:
type Product = {
title: string;
price: number;
inStock: boolean;
};
type ProductText = Product["title" | "price"];
// string | numberТут Product["title" | "price"] означає:
type ProductText = Product["title"] | Product["price"];Для властивостей із однаковим типом результатом буде один тип:
type User = {
firstName: string;
lastName: string;
age: number;
};
type UserNames = User["firstName" | "lastName"];
// stringIndexed Access Types можна застосовувати до масивів.
Для отримання типу одного елемента масиву використовують індекс number:
const colors = ["red", "green", "blue"];
type Color = typeof colors[number];
// stringЗапис:
typeof colors[number]означає «тип будь-якого елемента масиву colors».
Оскільки звичайний масив може містити елементи за індексами 0, 1, 2 та іншими числовими індексами, для його елементів використовують тип number.
const scores = [10, 20, 30];
type Score = typeof scores[number];
// numberОтриманий тип можна використовувати для параметрів функцій:
const colors = ["red", "green", "blue"];
type Color = typeof colors[number];
function printColor(color: Color): void {
console.log(color);
}
printColor("yellow");У цьому прикладі Color дорівнює string, тому "yellow" є допустимим значенням.
as constЗвичайний масив рядків має тип string[]. Якщо потрібно отримати об’єднання конкретних значень, використовуйте as const.
const colors = ["red", "green", "blue"] as const;
type Color = typeof colors[number];
// "red" | "green" | "blue"Тепер Color може бути лише одним із трьох значень:
const colors = ["red", "green", "blue"] as const;
type Color = typeof colors[number];
function printColor(color: Color): void {
console.log(color);
}
printColor("red");
printColor("green");
// Помилка: "yellow" не входить до типу Color
// printColor("yellow");Без as const TypeScript розширює елементи масиву до типу string:
const colors = ["red", "green", "blue"];
type Color = typeof colors[number];
// stringЗ as const елементи залишаються конкретними літеральними типами:
const colors = ["red", "green", "blue"] as const;
type Color = typeof colors[number];
// "red" | "green" | "blue"Кортеж — це масив із фіксованою кількістю елементів, типи яких відомі за позиціями.
const point = [10, 20] as const;
type X = typeof point[0];
// 10
type Y = typeof point[1];
// 20
type Coordinate = typeof point[number];
// 10 | 20Для кортежу можна отримати тип елемента за конкретним індексом:
type Pair = [string, number];
type PairName = Pair[0];
// string
type PairCount = Pair[1];
// numberІндекс number повертає об’єднання типів усіх елементів кортежу:
type Pair = [string, number];
type PairElement = Pair[number];
// string | numberУ наступному прикладі:
тип Product отримується з об’єкта через typeof;
тип ProductId отримується з властивості;
тип ProductTag отримується з елементів масиву;
тип Status отримується з кортежу конкретних значень.
const product = {
id: 101,
title: "Механічна клавіатура",
price: 2500,
tags: ["keyboard", "usb", "office"] as const,
status: "available" as const,
};
type Product = typeof product;
type ProductId = Product["id"];
type ProductTitle = Product["title"];
type ProductTag = Product["tags"][number];
type ProductStatus = Product["status"];
function showProduct(
id: ProductId,
title: ProductTitle,
tag: ProductTag,
status: ProductStatus,
): void {
console.log(`${id}: ${title}`);
console.log(`Тег: ${tag}`);
console.log(`Статус: ${status}`);
}
showProduct(
product.id,
product.title,
product.tags[0],
product.status,
);У цьому прикладі типи мають такі значення:
// ProductId — number
// ProductTitle — string
// ProductTag — "keyboard" | "usb" | "office"
// ProductStatus — "available"typeof у типі та під час виконанняconst age = 30;
console.log(typeof age); // "number"
type Age = typeof age;
// numberУ першому випадку результатом є значення "number". У другому — тип number.
Indexed Access Type працює з типом:
type Product = {
title: string;
};
// Правильно
type Title = Product["title"];Не слід писати значення безпосередньо в позиції типу:
const product = {
title: "Книга",
};
// Правильно: спочатку отримуємо тип об'єкта
type Product = typeof product;
type Title = Product["title"];type Product = {
title: string;
price: number;
};
// Помилка: "color" не є властивістю Product
// type Color = Product["color"];Назва властивості повинна існувати в типі.
as constconst statuses = ["new", "paid", "shipped"];
type Status = typeof statuses[number];
// stringЯкщо потрібні конкретні значення, використовуйте as const:
const statuses = ["new", "paid", "shipped"] as const;
type Status = typeof statuses[number];
// "new" | "paid" | "shipped"Для отримання типу елемента масиву використовуйте number:
const numbers = [1, 2, 3];
type NumberItem = typeof numbers[number];
// numbertypeof numbers[0] теж може отримати тип першого елемента, але typeof numbers[number] описує тип елемента за будь-яким числовим індексом.
Створіть об’єкт book із властивостями:
title;
author;
year;
genres, який є незмінним масивом жанрів.
Після цього:
отримайте тип усього об’єкта через typeof;
отримайте тип title;
отримайте тип елемента масиву genres;
створіть функцію, яка приймає жанр книги та виводить його в консоль.
Орієнтовна структура:
const book = {
title: "Кобзар",
author: "Тарас Шевченко",
year: 1840,
genres: ["poetry", "classic"] as const,
};
type Book = typeof book;
type BookTitle = Book["title"];
type Genre = Book["genres"][number];
function printGenre(genre: Genre): void {
console.log(`Жанр: ${genre}`);
}
printGenre(book.genres[0]);typeof у звичайному коді повертає інформацію про тип під час виконання.
typeof у позиції типу вилучає тип змінної або значення.
Indexed Access Type має форму Type["property"].
За допомогою Type["property"] можна отримати тип окремої властивості.
За допомогою ArrayType[number] можна отримати тип елементів масиву.
Для отримання об’єднання конкретних значень масиву використовуйте as const.
Для кортежів можна звертатися до елементів за конкретним індексом або використовувати number для всіх елементів.