Начало работы

Настройка занимает минут пять: поставить пакет, добавить Vite-плагин и подключить типы в tsconfig. Дальше вы пишете обычный TypeScript, а t12n сам вставляет проверки.

Установка

npm i t12n
# также: pnpm add t12n · yarn add t12n · bun add t12n

В этом одном пакете есть всё: Vite-плагин, рантайм, DOM-переопределения и тип-маркер Check<T>.

Подключение типов

Добавьте однострочную triple-slash-ссылку в любой амбиентный .d.ts, который уже подключён в проекте (например env.d.ts или новый t12n.d.ts):

/// <reference types="t12n" />

Это подгрузит DOM-переопределения, которые помечают fetch().json(), localStorage.getItem и подобное как Unvalidated<T>, и сделает тип-маркер Check<T> доступным.

Предпочитайте ссылку, а не "types": ["t12n"] в tsconfig.json — массив types там выключает авто-подключение всех остальных амбиентных пакетов (node, vite/client, глобалы тестов…). Ссылка подгружает глобалы t12n без этого побочного эффекта. И это необязательно: рантайм-проверки работают и без неё — она лишь добавляет компайл-тайм-давление и глобальный Check<T> (его можно и просто import type { Check } from 't12n').

Регистрация Vite-плагина

// vite.config.ts
import { defineConfig } from 'vite'
import t12n from 't12n/vite'

export default defineConfig({
  plugins: [t12n()],
})

Это вся конфигурация — t12n() по умолчанию работает в режиме auto. Дальше всё автоматически.

Первая проверка

Ничего вызывать или импортировать не нужно. Поставьте аннотацию типа на данные, которые приходят извне, — плагин видит границу, выводит схему из типа и вставляет проверку в нужной точке:

import type { User } from './types'

const user: User = await fetch('/api/me').then(r => r.json())

console.log(user.email)

На сборке это, по сути, превращается в:

import { __check } from 't12n/runtime'

const user = __check(
  await fetch('/api/me').then(r => r.json()),
  { kind: 'object', properties: {
    id:    { kind: 'string' },
    email: { kind: 'string' },
    age:   { kind: 'number' },
  } }
)

Схема — это обычные данные, не Zod-вызовы: t12n ходит со своим валидатором и без единой рантайм-зависимости. Форма с __check — наглядная модель; в прод-сборке плагин компилирует каждый тип в отдельную функцию, которая работает примерно в 8× быстрее Zod. Если ответ не совпал с UserValidationError с точным путём, ожидаемым типом и пришедшим значением.

Куда дальше