Типы: null, undefined, void, never

null, undefined, void и never — четыре специальных типа TypeScript для отсутствующих, несуществующих или невозможных значений, каждый со своей семантикой и правилами использования.

Зачем нужно

Эти типы описывают «отсутствие значения» по-разному: null — намеренное отсутствие, undefined — неинициализированное, void — функция ничего не возвращает, never — код никогда не достигается. Понимание различий критично при strictNullChecks.

Где используется

  • null — намеренное «нет значения» в полях объектов и возвратах функций
  • undefined — неинициализированные переменные, отсутствующие опциональные поля
  • void — возвращаемый тип функций без return-значения и callback-ов
  • never — exhaustive check, функции-исключения, фильтрация union

Основной контент

null — намеренное отсутствие

// С strictNullChecks: true
function findUser(id: string): User | null {
  return users.find(u => u.id === id) ?? null;
}

const user = findUser("u-1");
// user.name; // Error: Object is possibly 'null'
if (user !== null) {
  console.log(user.name); // OK
}

// Optional chaining
const name = findUser("u-1")?.name ?? "Guest";

undefined — неинициализированное

let x: string;
// console.log(x); // Error: Variable 'x' is used before assignment

// Опциональные свойства — undefined
interface Config {
  host: string;
  port?: number; // number | undefined
}

function getPort(config: Config): number {
  return config.port ?? 3000; // если undefined — дефолт
}

// Разница null vs undefined:
const obj = { a: null, b: undefined };
"a" in obj; // true
"b" in obj; // true
obj.a === null;      // true
obj.b === undefined; // true

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

// Функция с void return type
function log(message: string): void {
  console.log(message);
  // return;           // OK
  // return undefined; // OK
  // return "value";   // Error
}

// void в callback — важный нюанс
type Callback = () => void;

const cb: Callback = () => {
  return 42; // OK! void означает «возвращаемое значение игнорируется»
};

const result = cb; // result: void (нельзя использовать как number)

// forEach ожидает  => void — push возвращает number, но это OK
[1, 2, 3].forEach((n) => .push(n));

never — недостижимый код

// 1. Функции которые никогда не завершаются нормально
function throwError(message: string): never {
  throw new Error(message);
}

function infiniteLoop: never {
  while (true) {}
}

// 2. Exhaustive check
type Shape = { kind: "circle" } | { kind: "square" };

function describe(shape: Shape): string {
  switch (shape.kind) {
    case "circle": return "Круг";
    case "square": return "Квадрат";
    default:
      const _never: never = shape; // Error если добавить вариант без case
      return _never;
  }
}

// 3. Невозможные пересечения
type Impossible = string & number; // never

// 4. never в union «исчезает»
type A = string | never;  // string
type B = number | never;  // number

Сравнительная таблица

null undefined void never
Присваивается null undefined undefined ничто
Использование отсутствие неинициализировано нет return недостижимо
Assignable к any Да Да Да Да
Assignable к unknown Да Да Да Да

Частые ошибки

  • Путать undefined и опциональный (?)x?: string это string | undefined; x: undefined — всегда undefined.
  • Думать что void === undefined — в callback void разрешает вернуть любое значение; как тип переменной voidundefined.
  • Не проверять null при strictNullChecks — без проверки нельзя использовать nullable тип.
  • Не добавлять exhaustive check с never — без assertNever добавление варианта в union не вызовет ошибку компиляции.

Связанные темы

Ресурсы