Основные понятия

Несколько идей объясняют, как работает t12n. Когда они в голове, остальной API читается легко.

Граница

Граница — это любое место, где в программу приходят данные, которые вы не писали сами: ответ fetch, localStorage, postMessage, JSON.parse.

Внутри вашего кода типы гарантирует компилятор. На границе они — лишь предположение о данных, которые вы не контролируете. t12n проверяет это предположение, чтобы вам не приходилось ему просто доверять. Какие границы детектятся и как ими управлять — в разделе Границы и режимы.

Check<T> — тип-маркер

Check<T> — это identity-тип:

type Check<T> = T

На этапе компиляции ведёт себя ровно как T: ни narrowing’а, ни бренда, ничего в рантайме. Плагин узнаёт аннотацию по имени и читает её как: «выведи схему для T и оберни правую часть в проверку здесь».

const u: Check<User> = somewhere()       // переменная
function f(u: Check<User>) { /* … */ }   // параметр
function g(): Check<User> { /* … */ }    // возвращаемый тип

Везде, где TypeScript принимает аннотацию, Check<T> работает. Плагин ещё и переписывает эмитимый тип обратно на чистый T, чтобы дальнейшие потребители видели нормальную форму. Это явный триггер для manual-режима.

Unvalidated<T> — бренд границы

Два брендированных типа живут в пакете:

type Unvalidated<T> = T & { readonly [__unvalidated]: true }
type Validated<T>   = T & { readonly [__validated]:   true }

Бренд — unique symbol, подделать снаружи пакета нельзя. С загруженными DOM-переопределениями (через /// <reference types="t12n" />) fetch().json() возвращает Promise<Unvalidated<unknown>> — и компилятор не даёт использовать это как что-то ещё, пока оно не прошло через проверку.

Auto-режим снимает бренд: когда t12n вставляет рантайм-проверку на типизированной границе, результат трактуется как T (уже не Unvalidated<T>) на последующих использованиях.

Три принципа

  1. Тип — источник правды. Схемы выводятся из ваших TypeScript-типов, так что нет второго определения, которое может разойтись с первым.
  2. Вы включаете проверку местом, а не вызовом. Что проверять — зависит от того, куда вы поставили аннотацию, а не от вызова функции.
  3. Падения громкие и точные. Когда данные не подходят, ошибка называет поле, ожидаемый тип и реальное значение и срабатывает на строке, где данные пришли.

Вот и вся модель. Что работает под капотом — вывод схемы и компилируемый валидатор — см. движок.