Skip to main content

Що таке type narrowing у TypeScript?

Що таке Type Narrowing

Type narrowing (звуження типу) - це процес, під час якого TypeScript уточнює тип змінної на основі логічних перевірок, операторів та контексту виконання коду.

Простіше кажучи: TypeScript "спостерігає" за твоїми if, typeof, in, instanceof та іншими перевірками - і розуміє, який тип реально можливий у кожній гілці коду.


Приклад: без narrowing

javascript
function printId(id: string | number) { console.log(id.toUpperCase()); // Помилка - id може бути number }

id має тип string | number, і TypeScript не знає, який із них використовується зараз.


Приклад з narrowing

javascript
function printId(id: string | number) { if (typeof id === "string") { // Тут id: string console.log(id.toUpperCase()); } else { // Тут id: number console.log(id.toFixed(2)); } }

TypeScript звузив тип змінної id: у першій гілці string, у другій - number.


Як працює narrowing

TypeScript аналізує контроль потоку (control flow analysis) і автоматично "відсікає" неможливі типи, коли зустрічає:

  • перевірки typeof, instanceof, in, ===, !==, ==, !=;
  • перевірки на null / undefined;
  • користувацькі type guards (value is Type);
  • логічні вирази (if, else, switch, return, throw тощо).

Основні способи звуження типів

СпосібОписПриклад
typeofДля примітивівtypeof x === "string"
instanceofДля класів і конструкторівx instanceof Date
inПеревіряє наявність властивості"prop" in obj
=== / !==Порівняння літеральних значеньx === null
Перевірка null / undefinedВиключає "порожні" значенняif (x)
Користувацький type guardФункція вигляду x is TisArray(value): value is any[]

Приклади різних варіантів narrowing

1. typeof - примітиви

javascript
function log(value: string | number | boolean) { if (typeof value === "string") { value.toUpperCase(); // string } else if (typeof value === "number") { value.toFixed(2); // number } else { value.valueOf(); // boolean } }

2. instanceof - класи та об'єкти

javascript
function logDate(d: Date | string) { if (d instanceof Date) { d.toISOString(); // Date } else { d.toUpperCase(); // string } }

3. in - перевірка наявності властивості

javascript
type Dog = { bark: () => void }; type Cat = { meow: () => void }; function speak(animal: Dog | Cat) { if ("bark" in animal) { animal.bark(); // Dog } else { animal.meow(); // Cat } }

4. Перевірки == null

javascript
function greet(name?: string | null) { if (name == null) { console.log("No name provided"); } else { console.log("Hello, " + name.toUpperCase()); } }

Після if (name == null) TypeScript звужує тип до null | undefined, а після else - до string.


5. З користувацьким type guard

javascript
function isString(value: unknown): value is string { return typeof value === "string"; } function print(value: unknown) { if (isString(value)) { value.toUpperCase(); // тепер точно string } }

Користувацькі type guards - це спосіб навчити TS "розпізнавати" твої власні типи.


6. З літеральними типами та порівняннями

javascript
type Status = "loading" | "success" | "error"; function handle(status: Status) { if (status === "loading") { // status: "loading" } else if (status === "success") { // status: "success" } else { // status: "error" } }

Це окремий випадок discriminated union narrowing (звуження за дискримінуючою властивістю).


Звуження в об'єднаних типах (Union Narrowing)

Якщо змінна має тип A | B | C, TypeScript звузить його до конкретного підтипу, коли умова виключить решту.

javascript
function example(x: string | number | boolean) { if (typeof x === "string") { // string } else if (typeof x === "number") { // number } else { // boolean } }

Звуження з never

Коли TypeScript виключає всі можливі варіанти, змінна отримує тип never (недосяжний тип).

javascript
function process(value: string | number) { if (typeof value === "string") { return value.toUpperCase(); } else if (typeof value === "number") { return value.toFixed(2); } else { // value: never (сюди потрапити не можна) throw new Error("Unexpected type"); } }

Чому це важливо

Безпека: TS не дасть викликати метод, який не належить типу.

Зручність: IDE підказує доступні властивості й методи після narrowing.

Ясність коду: Можна писати чисті if/switch, без зайвих кастів (as).

Основа discriminated unions: Без narrowing TS не зміг би розуміти, який варіант union-типу використовується.


Підсумок

ПоняттяОпис
Type narrowingПроцес уточнення типу змінної на основі умов
Навіщо потрібноЩоб TypeScript знав, який підтип реально використовується в конкретному місці
Коли спрацьовуєПри перевірках (typeof, instanceof, in, ===, is, null тощо)
РезультатTS "звужує" union або unknown тип до конкретного
Тип "never"Використовується, коли інших варіантів не залишається

Просто запам'ятай:

Type narrowing - це коли TypeScript "думає як людина": він читає твій if і розуміє, який тип значення всередині кожної гілки.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.