Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що означає "union narrowing"?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Union narrowing** - це звуження union-типу до одного чи кількох конкретних членів об'єднання на основі перевірок у коді, таких як `typeof`, `instanceof`, `in` чи власні type guards. **Ключове:** завдяки narrowing TypeScript сам визначає точний підтип у кожній гілці коду, тож не доводиться писати `as Type` вручну.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що таке *union type* Спочатку нагадаємо, що **union type** (`A | B | C`) - це тип, який може бути **одним із кількох варіантів**. ```javascript type Result = string | number; ``` Змінна типу `Result` може бути **рядком або числом**: ```javascript let value: Result; value = "hello"; // string value = 42; // number ``` Але поки TypeScript не знає, **що саме зараз усередині**, він не дозволить використовувати специфічні властивості. ```javascript value.toFixed(); // Помилка - може бути string ``` --- ## Що таке *narrowing* (звуження) **Narrowing** - це процес, під час якого TypeScript **зменшує множину можливих типів**, спираючись на перевірки в коді. --- ## Що таке *union narrowing* **Union narrowing** - це звуження типу **з об'єднання (**`union`**)** до **одного або кількох конкретних членів цього об'єднання**, залежно від логічних умов, операторів чи перевірок. --- ### Приклад 1. Звуження за допомогою `typeof` ```javascript 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` ```javascript 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. Звуження через літеральну властивість ```javascript 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` ```javascript function logDate(d: Date | string) { if (d instanceof Date) { // d: Date console.log(d.toISOString()); } else { // d: string console.log(d.toUpperCase()); } } ``` --- ### Приклад 5. Звуження через перевірку `== null` ```javascript 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 ...`: ```javascript 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`, `switch` - `typeof` - `instanceof` - `in` - `===`, `!==`, `==`, `!=` - перевірки на `null` і `undefined` - власні guards (`v is T`) - `return` / `throw` / `break` (впливають на те, які гілки лишаються можливими) --- ## Приклад комбінованого narrowing ```javascript 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 точно знати, який тип використовується в кожній гілці коду |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.