Що таке type narrowing?
Що таке Type Narrowing (звуження типу)
Type narrowing - це процес, у якому TypeScript розуміє, який конкретно тип має значення в певній гілці коду і звужує загальний тип до більш конкретного.
Простіше кажучи: Якщо змінна може мати кілька типів (наприклад,
string | number), TypeScript "звужує" цей набір, коли ти робиш перевірки на кшталтtypeof,in,instanceofтощо.
Приклад 1. Звуження через typeof
function printId(id: string | number) {
if (typeof id === "string") {
// Тут id: string
console.log("Рядок:", id.toUpperCase());
} else {
// Тут id: number
console.log("Число:", id.toFixed(2));
}
}TypeScript сам розуміє:
- всередині
if (typeof id === "string")->idставstring - всередині
else->idставnumber
Приклад 2. Звуження через instanceof
class User {
constructor(public name: string) {}
}
class Admin {
constructor(public name: string, public permissions: string[]) {}
}
function printPerson(person: User | Admin) {
if (person instanceof Admin) {
// Тут person: Admin
console.log("Права:", person.permissions);
} else {
// Тут person: User
console.log("Звичайний користувач:", person.name);
}
}Приклад 3. Звуження через in (наявність властивості)
type User = { name: string };
type Admin = { name: string; permissions: string[] };
function printInfo(person: User | Admin) {
if ("permissions" in person) {
// person: Admin
console.log("Права:", person.permissions);
} else {
// person: User
console.log("Ім'я:", person.name);
}
}
inперевіряє наявність властивості, і TypeScript використовує це для логічного звуження типів.
Приклад 4. Звуження через ==, ===, !==, !=
TypeScript теж вміє "розуміти" тип після таких перевірок:
function process(value: string | null) {
if (value !== null) {
// value: string
console.log(value.toUpperCase());
}
}Приклад 5. Звуження через "truthy/falsy" значення
TypeScript знає, що null, undefined, 0, "", false - "falsy" значення.
function printName(name?: string) {
if (name) {
// name: string
console.log("Привіт,", name.toUpperCase());
} else {
// name: undefined
console.log("Ім'я не вказано");
}
}Приклад 6. Користувацькі перевірки типів (Type Guards)
Можна створити свою функцію, яка допомагає TypeScript звужувати тип:
type User = { name: string };
type Admin = { name: string; permissions: string[] };
function isAdmin(person: User | Admin): person is Admin {
return "permissions" in person;
}
function handle(person: User | Admin) {
if (isAdmin(person)) {
// Тут TS знає, що person: Admin
console.log("Права:", person.permissions);
} else {
// Тут person: User
console.log("Користувач:", person.name);
}
}
person is Admin- це user-defined type guard, який повідомляє TS, який саме тип повернеться з перевірки.
Приклад 7. Звуження всередині switch
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number }
| { kind: "triangle"; base: number; height: number };
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.side ** 2;
case "triangle":
return (shape.base * shape.height) / 2;
}
}Тут TypeScript використовує дискриміноване об'єднання і автоматично звужує тип у кожній гілці
case.
Де використовується type narrowing
| Сценарій | Приклад перевірки |
|---|---|
| Примітиви | typeof value === "string" |
| Класи | instanceof SomeClass |
| Об'єкти | "prop" in obj |
| Порівняння | if (x !== null) |
| Булеві перевірки | if (value) |
| Власні функції-охоронці | value is Type |
| switch-дискримінація | case "circle": … |
Навіщо це потрібно
Type narrowing дозволяє:
- працювати без помилок при union-типах;
- отримувати автодоповнення і підказки в IDE;
- писати безпечний і читабельний код без зайвих приведень типів (
as).
Коротко:
Type narrowing - це коли TypeScript "розуміє", який саме тип у змінної в певний момент, і автоматично звужує загальний тип до конкретного в різних гілках коду.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.