Union-типы, литеральные типы и strictNullChecks

Объединяем типы через вертикальную черту и берём под контроль коварные null и undefined.

Union-тип — тип «или одно, или другое», записывается через вертикальную черту: string | number.

Union-типы

Иногда значение может быть нескольких типов. Union перечисляет допустимые варианты:

let id: string | number;
id = 42;       // ок
id = "user-7"; // ок
id = true;     // Ошибка: Type 'boolean' is not assignable to type 'string | number'.

Это частая ситуация: идентификатор приходит то числом, то строкой. Union честно это описывает вместо ленивого any.

Сужение перед использованием

Со значением union-типа нельзя сразу делать операции, специфичные для одного из вариантов — нужно сначала разобраться, что это сейчас. Это называется сужением типа:

function printId(id: string | number) {
  if (typeof id === "string") {
    console.log(id.toUpperCase()); // тут id точно string
  } else {
    console.log(id.toFixed(2));    // а тут точно number
  }
}

Внутри каждой ветки TypeScript знает конкретный тип и разрешает соответствующие методы. Подробнее о сужении — в последнем разделе.

Литеральные типы

Тип может быть не «любая строка», а конкретное значение. Объединяя литералы через union, получаем перечисление допустимых вариантов:

type Direction = "up" | "down" | "left" | "right";

function move(dir: Direction) { /* ... */ }

move("up");   // ок
move("north"); // Ошибка: Argument of type '"north"' is not assignable to parameter of type 'Direction'.

Это мощная защита: вместо «принимаем любую строку и надеемся» компилятор гарантирует, что придёт только одно из четырёх значений. Опечатки исключены, а редактор подсказывает варианты.

Проблема null и undefined

Главный источник падений в JavaScript — обращение к свойству у null или undefined («Cannot read property of undefined»). Опция strictNullChecks (входит в strict) защищает от этого.

Со строгими проверками null нельзя положить в обычный тип:

let name: string = null;
// Ошибка: Type 'null' is not assignable to type 'string'.

Чтобы значение могло быть пустым, это указывают явно через union:

let name: string | null = null;

Компилятор требует проверки

Теперь обратиться к свойству, не проверив на null, нельзя — и это спасает от рантайм-падения:

function greet(name: string | null) {
  // name.toUpperCase();  // Ошибка: 'name' is possibly 'null'.
  if (name !== null) {
    console.log(name.toUpperCase()); // тут уже безопасно
  }
}

Без strictNullChecks первая строка прошла бы, и программа упала бы в рантайме на null. TypeScript превращает потенциальный краш в обязательную проверку.

Итог

  • Union A | B описывает значение нескольких типов; перед использованием его сужают.
  • Литеральные типы ("up" | "down") ограничивают значение конкретным набором — защита от опечаток.
  • strictNullChecks заставляет явно объявлять и проверять null/undefined, убирая целый класс падений.
Проверьте себя
1. Что описывает union-тип string | number?
AЗначение должно быть одновременно строкой и числом
BЗначение может быть либо строкой, либо числом
CМассив из строк и чисел
DФункцию, принимающую строку и число
2. Чем полезен литеральный union-тип "up" | "down" | "left" | "right"?
AОн ускоряет функцию
BОн ограничивает значение конкретным набором и защищает от опечаток
CОн позволяет передавать любую строку
DОн автоматически переводит строки в числа
3. Что даёт включённый strictNullChecks?
AЗапрещает использовать строки
BЗаставляет явно объявлять null/undefined и проверять значение перед использованием
CАвтоматически заменяет null на пустую строку
DОтключает проверку типов
Поддержать проект