Exhaustive check через never
Коротка відповідь: зроби дискримінований union і додай у switch "сторож" на основі типу never. Тоді при додаванні нового варіанта TypeScript видасть помилку компіляції.
Базовий прийом (exhaustive check через never)
javascript
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number }
| { kind: "triangle"; base: number; height: number };
function area(s: Shape): number {
switch (s.kind) {
case "circle":
return Math.PI * s.radius ** 2;
case "square":
return s.side ** 2;
case "triangle":
return (s.base * s.height) / 2;
default:
// якщо з'явиться новий варіант, тут s стане НЕ 'never' → помилка
const _exhaustive: never = s;
throw new Error(`Unhandled case: ${_exhaustive}`);
}
}- Коли ти додаси, наприклад,
{ kind: "rectangle" },sуdefaultперестане бутиnever→ помилка компіляції змусить дописатиcase.
Варіант із допоміжною функцією assertNever
Зручно, якщо ти часто робиш такі перевірки:
javascript
function assertNever(x: never): never {
throw new Error(`Unhandled case: ${String(x)}`);
}
function area(s: Shape): number {
switch (s.kind) {
case "circle": return Math.PI * s.radius ** 2;
case "square": return s.side ** 2;
case "triangle": return (s.base * s.height) / 2;
default: return assertNever(s); // тут спрацює помилка типів при новому варіанті
}
}Без default: "післясвітчевий" сторож
Якщо не хочеш default, можна вимагати, щоб усі гілки повертали значення,
а після switch - перевірити never:
javascript
function area(s: Shape): number {
switch (s.kind) {
case "circle": return Math.PI * s.radius ** 2;
case "square": return s.side ** 2;
case "triangle": return (s.base * s.height) / 2;
}
const _exhaustive: never = s; // спрацює при додаванні нового kind
return _exhaustive;
}Корисні налаштування та лінтинг
- ESLint-правило:
@typescript-eslint/switch-exhaustiveness-check- підсвічує незакритіswitch. - Прапорець компілятора
noFallthroughCasesInSwitchдопомагає уникати "протікань" міжcase(не про вичерпність, але корисно).
Підсумок
Щоб гарантувати, що switch обробив усі варіанти union:
- Використовуй дискриміноване поле (наприклад,
kind). - Додай exhaustive check через присвоєння до
never(уdefaultабо післяswitch). - (Опційно) Винеси перевірку в
assertNever.
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.