← Назад к вопросам

Можно ли использовать Never в Switch Case?

2.3 Middle🔥 201 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Можно ли использовать тип Never в конструкции Switch Case в TypeScript?

Да, тип Never можно и нужно использовать в switch-case, особенно в TypeScript, для реализации исчерпывающей проверки (exhaustiveness checking). Это мощный паттерн, гарантирующий безопасность кода во время компиляции.

Что такое тип Never?

Never — это специальный тип в TypeScript, представляющий значения, которые никогда не возникают. Он используется в ситуациях, которые никогда не должны происходить:

  • Возвращаемый тип функции, которая всегда выбрасывает исключение (throw new Error()).
  • Возвращаемый тип функции с бесконечным циклом.
  • Как тип переменной в ветке кода, которая недостижима.

Паттерн Exhaustiveness Checking с Never

Ключевое применение в switch — проверка, что обработаны все возможные варианты типа (обычно union type). Если мы добавим новый вариант в тип, но забудем добавить обработку в switch, TypeScript сообщит об ошибке компиляции.

Рассмотрим пример:

type Shape = 'circle' | 'square' | 'triangle';

function getArea(shape: Shape): number {
    switch (shape) {
        case 'circle':
            return Math.PI * 10 ** 2;
        case 'square':
            return 20 * 20;
        case 'triangle':
            return 0.5 * 10 * 15;
        default:
            // Здесь TypeScript проверяет исчерпываемость!
            const _exhaustiveCheck: never = shape;
            throw new Error(`Неизвестная форма: ${shape}`);
    }
}

Как это работает:

  1. В default ветке мы пытаемся присвоить переменной _exhaustiveCheck типа never значение shape.
  2. Пока switch обрабатывает все варианты типа Shape, код в default ветке недостижим, и shape в этой точке имеет тип never. Присваивание never = never допустимо.
  3. Добавим новый вариант в тип, но забудем про switch:
type Shape = 'circle' | 'square' | 'triangle' | 'hexagon'; // Добавили 'hexagon'

function getArea(shape: Shape): number {
    switch (shape) {
        case 'circle':
            return Math.PI * 10 ** 2;
        case 'square':
            return 20 * 20;
        case 'triangle':
            return 0.5 * 10 * 15;
        default:
            // ОШИБКА КОМПИЛЯЦИИ!
            // Тип '"hexagon"' не может быть присвоен типу 'never'.
            const _exhaustiveCheck: never = shape;
            throw new Error(`Неизвестная форма: ${shape}`);
    }
}

Вариации и лучшие практики

  • Использование assertNever: Часто проверку выносят в отдельную функцию для удобства повторного использования.
function assertNever(x: never): never {
    throw new Error(`Достигнут необрабатываемый вариант: ${x}`);
}

type Shape = 'circle' | 'square';

function getArea(shape: Shape): number {
    switch (shape) {
        case 'circle':
            return Math.PI * 10 ** 2;
        case 'square':
            return 20 * 20;
        default:
            // Если мы добавим в тип новый вариант, например 'triangle',
            // то эта строка вызовет ошибку компиляции,
            // так как shape уже не будет типом never.
            return assertNever(shape);
    }
}
  • Применение с Discriminated Unions: Паттерн особенно эффективен с различающимися (tagged) объединениями, где каждое значение имеет общее поле-метку (часто type или kind).
type Success = { type: 'success'; data: string };
type Error = { type: 'error'; message: string };
type Loading = { type: 'loading' };

type ApiState = Success | Error | Loading;

function handleState(state: ApiState) {
    switch (state.type) {
        case 'success':
            console.log(state.data);
            break;
        case 'error':
            console.error(state.message);
            break;
        case 'loading':
            console.log('Loading...');
            break;
        default:
            const _exhaustiveCheck: never = state;
            return _exhaustiveCheck;
    }
}

Итог

Использование never в switch-case — это не просто возможность, а один из лучших паттернов TypeScript для повышения надежности кода. Он превращает потенциальные ошибки времени выполнения (когда появляется непредусмотренное значение) в ошибки компиляции, которые легко обнаружить и исправить на этапе разработки. Это яркий пример того, как статическая типизация помогает писать более безопасный и поддерживаемый код, особенно в больших кодовых базах.

Можно ли использовать Never в Switch Case? | PrepBro