Що означає "union narrowing"?
Що таке union type
Спочатку нагадаємо, що union type (A | B | C) - це тип, який може бути одним із кількох варіантів.
type Result = string | number;Змінна типу Result може бути рядком або числом:
let value: Result;
value = "hello"; // string
value = 42; // numberАле поки TypeScript не знає, що саме зараз усередині, він не дозволить використовувати специфічні властивості.
value.toFixed(); // Помилка - може бути stringЩо таке narrowing (звуження)
Narrowing - це процес, під час якого TypeScript зменшує множину можливих типів, спираючись на перевірки в коді.
Що таке union narrowing
Union narrowing - це звуження типу з об'єднання (union)
до одного або кількох конкретних членів цього об'єднання,
залежно від логічних умов, операторів чи перевірок.
Приклад 1. Звуження за допомогою typeof
function printValue(value: string | number) {
if (typeof value === "string") {
// тут value: string
console.log(value.toUpperCase());
} else {
// тут value: number
console.log(value.toFixed(2));
}
}TypeScript "звузив" value з string | number
до string в одній гілці і number - в іншій.
Приклад 2. Звуження через перевірку in
type Cat = { kind: "cat"; meow: () => void };
type Dog = { kind: "dog"; bark: () => void };
function makeSound(animal: Cat | Dog) {
if ("meow" in animal) {
// animal: Cat
animal.meow();
} else {
// animal: Dog
animal.bark();
}
}Приклад 3. Звуження через літеральну властивість
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number };
function area(shape: Shape) {
if (shape.kind === "circle") {
// shape: { kind: "circle"; radius: number }
return Math.PI * shape.radius ** 2;
} else {
// shape: { kind: "square"; side: number }
return shape.side ** 2;
}
}Це приклад discriminated union narrowing
(звуження за дискримінатором - ключем kind).
Приклад 4. Звуження через instanceof
function logDate(d: Date | string) {
if (d instanceof Date) {
// d: Date
console.log(d.toISOString());
} else {
// d: string
console.log(d.toUpperCase());
}
}Приклад 5. Звуження через перевірку == null
function greet(name?: string | null) {
if (name == null) {
// name: null | undefined
console.log("No name provided");
} else {
// name: string
console.log("Hello, " + name);
}
}Приклад 6. Звуження через власні type guards
Можна оголосити свій "фільтр типів" - функцію, яка повертає value is ...:
type Car = { wheels: 4; drive: () => void };
type Bike = { wheels: 2; pedal: () => void };
function isCar(v: Car | Bike): v is Car {
return (v as Car).drive !== undefined;
}
function move(vehicle: Car | Bike) {
if (isCar(vehicle)) {
// vehicle: Car
vehicle.drive();
} else {
// vehicle: Bike
vehicle.pedal();
}
}Що TypeScript враховує під час narrowing
TypeScript уміє автоматично аналізувати контроль потоку:
if,else,switchtypeofinstanceofin===,!==,==,!=- перевірки на
nullіundefined - власні guards (
v is T) return/throw/break(впливають на те, які гілки лишаються можливими)
Приклад комбінованого narrowing
function process(val: string | number | boolean | null) {
if (typeof val === "string") {
// val: string
} else if (typeof val === "number") {
// val: number
} else if (val === null) {
// val: null
} else {
// val: boolean (тип, що залишився)
}
}Чому це важливо
Без narrowing TypeScript не зміг би гарантувати типову безпеку.
Він би не розумів, який тип використовується в конкретній точці програми,
і змушував би тебе писати as Type повсюди.
Завдяки union narrowing TypeScript вміє аналізувати логіку коду і автоматично обирати правильний підтип.
Підсумок
| Термін | Значення |
|---|---|
| Union Type | Об'єднання можливих типів (`A |
| Narrowing | Звуження множини можливих типів на основі умов |
| Union Narrowing | Звуження конкретно в об'єднанні типів |
| Як виконується | Через typeof, instanceof, in, перевірки літералів, guards |
| Головна мета | Дозволити TypeScript точно знати, який тип використовується в кожній гілці коду |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.