T extends never
1. Що таке never
Тип never означає:
"значення, яке ніколи не може існувати".
Приклади:
function fail(): never {
throw new Error("Error!");
}never - підтип усіх типів, але ніхто не є підтипом never,
крім самого never.
2. Що робить T extends never ? X : Y
Це умовний тип (conditional type), який можна прочитати як:
"Якщо тип
T- цеnever, повернутиX, інакше -Y."
Приклад:
type Check<T> = T extends never ? "YES" : "NO";
type A = Check<never>; // "YES"
type B = Check<string>; // "NO"
type C = Check<any>; // "NO"A поверне "YES", тому що T дійсно never.
3. Але! Особливість: умовні типи розподіляються по union-типах
Якщо T - об'єднання (A | B | C),
TypeScript застосовує умову окремо до кожного члена.
type Example<T> = T extends never ? "Y" : "N";
type R1 = Example<string | never | number>;
// Крок за кроком:
// string → "N"
// never → "Y"
// number → "N"
// R1 = "N" | "Y" | "N" → "N" | "Y"Навіть якщо всередині union є never,
він "розчиняється" (не впливає), і підсумок залишається "N" | "Y".
4. Чому never іноді "зникає" в union'ах
never - "поглинальний" елемент об'єднань:
string | never // → string
number | never // → numberТому при підстановці в T extends ... -
якщо T взагалі не існує (наприклад, після фільтрації),
результат не розподіляється і може перетворитися на never.
Приклад 1: перевірка "порожнього" типу
type IsNever<T> = [T] extends [never] ? true : false;
type A = IsNever<never>; // true
type B = IsNever<string>; // false
type C = IsNever<any>; // falseЧому квадратні дужки? Вони вимикають дистрибутивність, і перевірка виконується для типу цілком, а не для кожного члена union.
Приклад 2: без дужок - результат неочікуваний
type IsNeverDistributive<T> = T extends never ? true : false;
type A = IsNeverDistributive<never>; // never (!) - а не trueТому що умовний тип "розподілився" по порожній множині (never → немає членів → немає результату).
Тому результат став never, а не true.
Виправлення:
type IsNever<T> = [T] extends [never] ? true : false;Приклад 3: використання у фільтрації типів
type FilterNever<T> = T extends never ? never : T;
type A = FilterNever<string | never | number>;
// string | number"Відфільтрували" всі
neverз union-типу.
Приклад 4: перевірка в умовних утилітах
type SafeReturn<T> = T extends never ? "No value" : T;
type A = SafeReturn<never>; // "No value"
type B = SafeReturn<"ok">; // "ok"Коротко про механіку
| Ситуація | Що відбувається |
|---|---|
never extends never | true |
never extends anything else | true (оскільки never - підтип усіх типів) |
something extends never | false (крім самого never) |
T extends never ? X : Y | Поверне X, тільки якщо T === never |
T extends never ? X : Y (з union) | Розподіляється по кожному члену union |
[T] extends [never] ? X : Y | Перевіряє весь тип без розподілу |
Підсумок
| Перевірка | Поведінка | Приклад |
|---|---|---|
| Проста перевірка | T extends never ? X : Y | Check<never> → X |
| Неочікуваний розподіл | T = never дає never, не X | IsNeverDistributive<never> → never |
| Правильна перевірка | [T] extends [never] ? X : Y | IsNever<never> → true |
| Фільтрація | T extends never ? never : T | Прибирає never з union |
| Причина | never - "порожня множина типів" | Не містить значень, але підтип будь-якого типу |
Простіше кажучи
T extends never ? X : Y- умовний тип для перевірки "порожнечі".- Але при
T = neverвін сам перетворюється наnever. - Щоб коректно перевірити "чи є тип
never", потрібно загорнути тип у кортеж:type IsNever<T> = [T] extends [never] ? true : false;
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.