Способы, которыми TypeScript сужает тип внутри ветки, сгруппированные по приёмам: встроенные проверки, собственные предикаты, функции-утверждения, дискриминированные объединения, равенство и поток истинности, а также сужение через псевдонимы и отложенное. Каждая строка сочетает приём с однострочным примером.
Сужение (narrowing) — это то, как TypeScript превращает широкий тип в более узкий внутри ветки кода, чтобы доказать безопасность доступа к свойству. Каждая проверка (typeof, in, предикат, дискриминант) говорит компилятору: отсюда значение более конкретно. Приёмы ниже — рабочий набор.
Справочная таблица · 23 записи
Сужение типов в TypeScriptExplained
23 of 23 rows
Встроенные проверки
Сужает примитивы: string, number, boolean и другие.
if (typeof x === 'string') x.toUpperCase()
Сужает до экземпляра класса или конструируемого значения.
if (e instanceof Error) e.message
Сужает, проверяя наличие свойства у значения.
if ('id' in obj) obj.id
Сужает любое значение до массива; объединение — до его члена-массива.
if (Array.isArray(x)) x.map(f)
Собственные проверки
Функция-предикат, чей результат сужает аргумент.
function isUser(x): x is User { return !!x.id }
Предикат может сужать до объединения типов, а не только до одного.
function isKey(x): x is string | number
Предикат-пересечение сохраняет входной тип и добавляет к нему поля.
function hasId(x): x is x & { id: string }
Функция-утверждение, которая выбрасывает исключение, если x не является типом.
function assertUser(x): asserts x is User
Дискриминированные объединения
Сужает объединение по общему литеральному полю через switch или if.
type E = { kind: 'a'; a: number } | { kind: 'b'; b: string }
Каждая ветка case сужает до одного члена объединения.
switch (u.kind) { case 'a': u.a }
Сужает непомеченное объединение, когда свойство есть только у одного члена.
if ('b' in u) u.b
Каждая ветка case — условие; совпавшая ветка сужает значение.
switch (true) { case typeof x === 'string': }
Ветка default присваивает значение типу never, доказывая полноту switch.
default: { const x: never = u }
Равенство и поток
Убирает null и undefined после проверки на равенство.
if (x === null) return; x.toFixed()
Убирает ложные значения (0, '', null, undefined, NaN).
if (!x) return; // x is defined here
Истинное свойство в цепочке доказывает, что базовое значение присутствует.
if (user?.active) user.name
Не-null-утверждение убирает null и undefined без проверки.
x!.toFixed(2)
Определённое присваивание: объявляет, что x присваивается до первого чтения.
let name!: string; init()
Сужение действует внутри ветки и после ранних return.
if (!arr) return; arr.map(...)
Псевдонимы и отложенность
Константа const с булевым значением, хранящая проверку, сужает везде, где она проверяется.
const isStr = typeof x === 'string'; if (isStr) …
Переменная const сохраняет сужение внутри замыканий, которые её захватывают.
const s = get(); if (s) use(() => s.length)
Начиная с TS 5.4 переменная let или параметр сохраняет сужение в замыканиях после последнего присваивания.
let n: string | null = get(); if (n) use(() => n.length)
unknown нельзя использовать, пока проверка не сузит его до реального типа.