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

Для чего нужен тип Never?

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

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

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

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

Never тип — типизация функций, которые никогда не возвращают значение

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

Когда используется Never

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

// Функция работает бесконечно
function infiniteLoop(): never {
  while (true) {
    // Бесконечный цикл
  }
}

// Функция никогда не достигает конца
function assertNever(x: never): never {
  throw new Error(`Unreachable code: ${x}`);
}

Never vs Void

// ❌ Void — функция возвращает undefined
function log(message: string): void {
  console.log(message);
  return; // Возвращает undefined
}

const result1: undefined = log("Hello"); // Ошибка в TypeScript
// На самом деле log возвращает undefined

// ✅ Never — функция никогда не возвращает
function throwError(message: string): never {
  throw new Error(message); // Никогда не вернёт, даже undefined
}

const result2: never = throwError("Error"); // Никогда не достигнет этой строки

Практический пример: Exhaustiveness checking

type Status = "loading" | "success" | "error";

function handleStatus(status: Status): string {
  switch (status) {
    case "loading":
      return "Загружаем...";
    case "success":
      return "Готово!";
    case "error":
      return "Ошибка!";
    default:
      // ✅ TypeScript покажет ошибку если забыли обработать статус
      const _exhaustiveCheck: never = status;
      return _exhaustiveCheck;
  }
}

// Если добавить новый статус, TypeScript покажет ошибку
type NewStatus = "loading" | "success" | "error" | "pending";

function handleNewStatus(status: NewStatus): string {
  switch (status) {
    case "loading":
      return "Загружаем...";
    case "success":
      return "Готово!";
    case "error":
      return "Ошибка!";
    case "pending":
      return "В ожидании...";
    default:
      // ✅ Если забыли обработать "pending", ошибка уже здесь
      const _exhaustiveCheck: never = status;
      return _exhaustiveCheck;
  }
}

Never в объединённых типах (Union Types)

// Never удаляется из объединения
type A = string | never; // Результат: string
type B = number | never; // Результат: number
type C = never | "a" | "b"; // Результат: "a" | "b"

// Это полезно для условных типов
type Exclude<T, U> = T extends U ? never : T;

type NoString = Exclude<string | number | boolean, string>;
// Результат: number | boolean
// (string исключён, потому что вернёт never, который удаляется)

type NoFunction = Exclude<string | (() => void), Function>;
// Результат: string
// (функция исключена)

Использование Never для невозможных случаев

// Функция что-то на основе типа
function processValue(value: string | number): string {
  if (typeof value === "string") {
    return value.toUpperCase();
  } else if (typeof value === "number") {
    return value.toString();
  } else {
    // Это место никогда не должно быть достигнуто
    const _unreachable: never = value;
    throw new Error(`Unreachable: ${_unreachable}`);
  }
}

// React компонент с невозможными props
interface SuccessProps {
  type: "success";
  message: string;
}

interface ErrorProps {
  type: "error";
  error: Error;
}

type MessageProps = SuccessProps | ErrorProps;

function Message(props: MessageProps) {
  switch (props.type) {
    case "success":
      return <div>{props.message}</div>;
    case "error":
      return <div>Ошибка: {props.error.message}</div>;
    default:
      // Если типы обновлены, но обработчик забыли
      const _exhaustive: never = props;
      return _exhaustive;
  }
}

Never для функций обработки ошибок

// Функция, которая ВСЕГДА выбрасывает ошибку
function invariant(condition: any, message: string): asserts condition {
  if (!condition) {
    throw new Error(message);
  }
}

function parseNumber(value: string): number {
  const num = parseInt(value, 10);
  invariant(!isNaN(num), `Invalid number: ${value}`);
  // После проверки компилятор знает, что num — это number
  return num;
}

// Функция обработки ошибок (никогда не возвращает)
function handleError(error: Error): never {
  console.error(error);
  process.exit(1);
}

// API call с обработкой ошибок
async function fetchUser(id: number): Promise<User> {
  try {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) {
      handleError(new Error(`HTTP ${response.status}`));
    }
    return response.json();
  } catch (error) {
    handleError(error as Error);
  }
}

Never в условных типах

// Полезно для построения сложных типов
type IsAny<T> = unknown extends T ? (T extends any ? true : false) : false;

type TrueIfAny<T> = T extends never ? false : true;

// Получить ключи объекта, значение которых — функция
type FunctionPropertyNames<T> = {
  [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
}[keyof T];

interface MyObject {
  name: string;
  greet: () => void;
  count: number;
  calculate: (a: number) => number;
}

type FuncKeys = FunctionPropertyNames<MyObject>;
// Результат: "greet" | "calculate"

Never в Generic типах

// Создаём тип, который исключает undefined
type NonUndefined<T> = T extends undefined ? never : T;

type StringOrUndefined = NonUndefined<string | undefined>;
// Результат: string

type NeverType = NonUndefined<undefined>;
// Результат: never

// Практический пример: требуемые поля в форме
type FormField<T> = {
  value: T;
  error?: string;
};

type RequiredFields<T> = {
  [K in keyof T]: T[K] extends undefined ? never : FormField<T[K]>;
};

interface UserForm {
  name?: string;
  email?: string;
  age: number;
}

type ValidUserForm = RequiredFields<UserForm>;
// Только age будет типизирован как FormField

Важные замечания

// ✅ Never можно использовать как значение return type
function stopExecution(): never {
  throw new Error("Stop here");
}

// ❌ Нельзя создать переменную типа never
const x: never = "something"; // Ошибка!

// ✅ Но можно в типе
type ImpossibleType = {
  value: never;
};

// Если функция имеет return type never, она ДОЛЖНА выбросить или зависнуть
function badNever(): never {
  return undefined; // ❌ Ошибка компиляции
}

// ✅ Правильно
function goodNever(): never {
  throw new Error("Must throw");
}