Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Exhaustive check через never». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Exhaustive check** через `never` - прийом, коли після обробки всіх `case` дискримінованого union компілятор перевіряє, що залишковий тип змінної дорівнює `never`. **Ключове:** якщо додати новий варіант union без відповідного `case`, TypeScript видасть помилку компіляції ще до запуску.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)ЗображенняКоротка відповідь: зроби **дискримінований 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: 1. Використовуй **дискриміноване поле** (наприклад, `kind`). 2. Додай **exhaustive check** через присвоєння до `never` (у `default` або після `switch`). 3. (Опційно) Винеси перевірку в `assertNever`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.