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

В чем разница между Void и Never?

2.0 Middle🔥 201 комментариев
#TypeScript

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

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

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

В чем разница между Void и Never?

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

Void — "нет возвращаемого значения"

Void означает, что функция ничего не возвращает (или возвращает undefined). Это самый распространённый тип для функций, которые выполняют действия, но не возвращают результат.

// Функция ничего не возвращает
function printMessage(message: string): void {
  console.log(message);
  // return; — неявно возвращает undefined
}

// Это валидно
function greet(name: string): void {
  console.log(`Hello, ${name}`);
}

// Это тоже валидно (явный возврат undefined)
function sayGoodbye(): void {
  console.log('Bye!');
  return undefined;  // ✅ Допустимо
}

Never — "функция никогда не вернёт управление"

Never указывает, что функция никогда не завершит работу нормально. Функция либо выбросит исключение, либо будет работать бесконечно, либо завершит программу.

// Функция выбрасывает исключение
function throwError(message: string): never {
  throw new Error(message);
}

// Функция бесконечный цикл
function infiniteLoop(): never {
  while (true) {
    // do something forever
  }
}

// Функция завершает процесс
function exitProcess(): never {
  process.exit(1);
}

Основные различия

АспектVoidNever
Возвращаемое значениеundefinedНет возврата
ЗавершениеФункция завершается нормальноФункция никогда не завершается
ПримерыЛогирование, обновление DOMThrow, бесконечный цикл
ИспользованиеЧастое в обычном кодеРедкое, для специальных случаев

Практические примеры

Void в обработчиках событий:

// Обработчик события ничего не возвращает
const handleClick = (): void => {
  console.log('Button clicked');
  updateUI();
};

// React компонент с обработчиком
function Button() {
  return (
    <button onClick={(): void => console.log('Clicked!')}>
      Click me
    </button>
  );
}

Never в функциях-ошибок:

// Функция для выброса ошибок
function assertNotNull<T>(value: T | null): asserts value is T {
  if (value === null) {
    throw new Error('Value is null');
  }
}

// Функция, которая должна прекратить выполнение
function handleError(error: Error): never {
  console.error('Critical error:', error);
  throw error;
}

// Функция для логирования и завершения
function fatal(message: string): never {
  console.error('FATAL:', message);
  process.exit(1);
}

Never в type guards и exhaustiveness checking

Never используется для проверки того, что все ветви switch обработаны:

type Status = 'success' | 'error' | 'pending';

function handleStatus(status: Status): void {
  switch(status) {
    case 'success':
      console.log('Success!');
      break;
    case 'error':
      console.log('Error!');
      break;
    case 'pending':
      console.log('Pending...');
      break;
    default:
      // Если забыть обработать статус, здесь будет тип never
      const exhaustive: never = status;  // Ошибка типа!
  }
}

// Добавили новый тип
type StatusNew = 'success' | 'error' | 'pending' | 'timeout';

function handleStatusNew(status: StatusNew): void {
  switch(status) {
    case 'success':
      console.log('Success!');
      break;
    case 'error':
      console.log('Error!');
      break;
    case 'pending':
      console.log('Pending...');
      break;
    // Забыли 'timeout' — здесь TypeScript ошибка!
    default:
      const exhaustive: never = status;  // TS Error!
  }
}

Never в условных типах (Conditional Types)

// Удаление null и undefined типов
type NonNullable<T> = T extends null | undefined ? never : T;

type A = NonNullable<string | null>;  // string
type B = NonNullable<number | undefined>;  // number
type C = NonNullable<null | undefined>;  // never

// Фильтрация типов
type FunctionType<T> = T extends (...args: any[]) => any ? T : never;

type IsFn = FunctionType<() => void>;  // () => void
type NotFn = FunctionType<string>;  // never

Практический пример: обработка ошибок

// Функция с void — обработка без выброса
function logWarning(message: string): void {
  console.warn('Warning:', message);
}

// Функция с never — критическая ошибка
function logAndThrow(message: string): never {
  console.error('Critical:', message);
  throw new Error(message);
}

// Использование
function process(value: any): void {
  if (!value) {
    logWarning('Value is empty');  // Продолжает работу
  }
  
  if (value.id === undefined) {
    logAndThrow('ID is required');  // Прерывает программу
  }
}

Best Practices

✅ Используй Void:

// Для функций, выполняющих действия
function sendNotification(message: string): void {
  // отправляет уведомление
}

// Для обработчиков событий
const onClick = (): void => { /* ... */ };

✅ Используй Never:

// Для функций обработки ошибок
function panic(message: string): never {
  throw new Error(message);
}

// Для exhaustiveness checking
default:
  const exhaustive: never = unknownValue;

❌ Не путай:

// Плохо: void где нужна never
function badError(): void {
  throw new Error('Oops');
}

// Хорошо: never для ошибок
function goodError(): never {
  throw new Error('Oops');
}

Суммируя: Void — это тип для функций, которые завершаются нормально и ничего не возвращают. Never — это тип для функций, которые никогда не вернут управление нормально (выброс ошибки, бесконечный цикл). Правильное использование этих типов делает код более безопасным и позволяет TypeScript лучше помогать с проверкой типов.