JSON в TypeScript
Автоматическая конвертация JSON-данных в TypeScript-интерфейсы или определения типов
// После ввода JSON автоматически сгенерируются определения типов TypeScriptЧто такое конвертация JSON в TypeScript?
JSON to TypeScript анализирует структуру JSON и создает на ее основе интерфейсы или псевдонимы типов TypeScript. Инструмент полезен, когда ответы API, конфигурационные файлы, тестовые payload или mock-данные нужно быстро перенести в типизированный frontend- или Node.js-проект. Он определяет объекты, массивы, вложенные поля, необязательные свойства и базовые типы, превращая сырые данные в основу для автодополнения и проверок компилятора. Но результат требует проверки: один пример JSON может не содержать всех полей, пустые массивы не показывают структуру элементов, а реальные API могут возвращать null или разные формы объектов. Для production-данных или кодовой базы результат все равно нужно проверить parser, тестами или правилами проекта.
Как использовать
Как использовать
- Вставьте JSON-данные в левое поле ввода или нажмите кнопку примера, чтобы загрузить образец
- Настройте параметры: задайте имя корневого типа, выберите стиль interface/type, добавьте export и т. д.
- Определения типов TypeScript генерируются автоматически справа
- Нажмите кнопку 'Копировать', чтобы скопировать сгенерированные определения типов в буфер обмена
- Вставьте определения типов в ваш TypeScript-проект
Советы по генерации типов
- Используйте показательные примеры JSON. Один образец не покажет все необязательные поля, значения null и объединённые типы, которые встречаются в реальном API.
- Проверьте сгенерированные имена, особенно для вложенных объектов, где автоматические имена интерфейсов могут быть слишком общими.
Применение
Технический принцип
JSON to TypeScript — это по сути процесс «вывода структуры». Инструмент рекурсивно обходит каждый узел дерева JSON, отображая тип каждого значения из рантайма в тип TypeScript: string -> string, number -> number, boolean -> boolean, null -> null, object -> суб-интерфейс, array -> массив типа элемента. Результат — набор объявлений TypeScript `interface` (или алиасов `type`, если выбран режим вывода 'type') плюс все вложенные интерфейсы, извлечённые из полей со значениями-объектами. Сложная часть вывода — решение о union-против-единственного-типа для массивов. Когда все элементы массива одного типа, результат — `T[]` (однородный массив). Когда элементы разных типов, результат — объединение этих типов: `[1, 'a', true]` становится `(number | string | boolean)[]`. Когда входные данные — объект, смешивающий литеральные и структурированные значения (например, `{ id: 1, name: 'Alice', tags: ['admin', 'editor'] }`), каждое поле получает свой тип; для объектов со смешанными примитивными значениями страница выдаёт единый интерфейс, а не union, потому что именно этого ожидает TypeScript-код (и это соответствует природе JSON-объекта как типа-записи). Несколько образцовых объектов (типичный сценарий: вставить JSON-массив) объединяются пересечением их форм. Поля, присутствующие в каждом образце, становятся обязательными; поля, отсутствующие в каком-либо образце, становятся необязательными (`fieldName?: T`). Это правильное поведение для ответов API: ответ 200 OK — одна форма, ответ 404 — другая, а объединение обоих даёт правильный TS-тип. Для одного образца все поля обязательны. Нормализация имён — это где большинство инструментов «JSON to TS» проигрывают. Ключи JSON обычно в snake_case (`user_id`, `created_at`) или camelCase (`userId`, `createdAt`); конвенция TypeScript — PascalCase для имён интерфейсов (`UserProfile`, `AuditEntry`) и camelCase для имён свойств. Страница конвертирует ключи JSON в camelCase (или сохраняет их, если они уже в camelCase или однословные) и PascalCase для имён интерфейсов. Внутренние объекты извлекаются в именованные интерфейсы: `{ user: { name, age } }` становится `interface User { name: string; age: number; }`, а родитель становится `interface Root { user: User; }`. Рекурсивные структуры (узел дерева с полем `children: TreeNode[]`) получают самоссылку через предварительное объявление `type` вместо `interface`, чтобы цикл был корректно определён. Переключатель «root» — это разница между массивным и объектным корнем. JSON-массив становится `type Root = Item[]` или `interface Root { items: Item[]; ... }` в зависимости от переключателя wrap-array. JSON-объект становится плоским интерфейсом на верхнем уровне. Строки-даты (RFC 3339 / ISO 8601) можно пометить как `Date` вместо `string`; UUID, email и URL можно пометить как branded-типы (`type UUID = string & { readonly __brand: 'UUID' };`), когда включён переключатель строгого режима. Генерация JSDoc эвристична: поле с именем `email` (и значением, соответствующим базовому regex email) получает комментарий вроде `/** user email */` над объявлением. То же самое для `id`, `name`, `url`, `created_at`/`createdAt`, `updated_at`/`updatedAt`, `description`, `title`. Комментарии — лучшая попытка, а не претензия на ручное написание; это отправная точка, которую люди будут редактировать. Страница также выдаёт модификаторы `export`, чтобы результат можно было вставить в любой TS-файл как есть, и заголовок `// generated by json-to-typescript, do not edit by hand`, чтобы отговорить от ручных правок, которые будут затёрты при следующей регенерации схемы.
- Атомарное отображение типов: string/number/boolean/null из JSON отображаются один к одному в string/number/boolean/null TypeScript. Большие целые числа (>2^53) требуют BigInt; страница помечает их как `bigint`, когда значение превышает Number.MAX_SAFE_INTEGER.
- Вывод типа массива: обход всех элементов и взятие объединения их типов; одинаковые типы сворачиваются в `T[]`, различные формируют `(A | B | C)[]`. Пустые массивы становятся `unknown[]`, так как тип элемента неизвестен.
- Извлечение вложенных объектов: внутренние объекты автоматически поднимаются в именованные интерфейсы. Рекурсивные структуры используют `type Name = ...` (не `interface`), чтобы предварительная ссылка была корректно определена в проверке типов TypeScript.
- Определение необязательных полей: при объединении нескольких образцовых объектов поля, присутствующие в каждом образце, становятся обязательными; поля, отсутствующие в каком-либо образце, становятся необязательными (`fieldName?: T`). Ввод с одним образцом помечает все поля обязательными.
- Конвенция именования: ключи JSON конвертируются в camelCase для имён свойств (user_id -> userId, created_at -> createdAt) и PascalCase для имён интерфейсов (UserProfile, AuditEntry). Однословные ключи сохраняются; цифры в ключах сохраняются; ведущие цифры дополняются подчёркиванием для сохранения валидных TS-идентификаторов.
- Переключатель root: массивный корень -> `export type Root = Item[]` (или обёрнутый в `{ items: Item[]; }`, если включён wrap-array); объектный корень -> единый `export interface Root { ... }`. Рекурсивные структуры сначала получают заглушку предварительного объявления.
- JSDoc-комментарии: эвристическая генерация комментариев для известных имён полей (email, id, name, url, createdAt, updatedAt, description, title). Вывод включает модификаторы `export` и заголовок `// generated, do not edit by hand` для отговорки от ручных правок.
- Строгий режим: опциональное включение branded-типов (UUID, Email, URL, Date), модификаторов readonly, exactOptionalPropertyTypes и noUncheckedIndexedAccess. Страница выдаёт `type UUID = string & { readonly __brand: 'UUID' };`, когда строгий режим включён, чтобы нисходящий код мог отличить сырую строку от типизированного значения.
Примеры
Простой объект в interface
{"id": 1, "name": "Alice", "active": true}
->
interface User {
id: number;
name: string;
active: boolean;
}Вложенный объект порождает суб-интерфейсы
{"user": {"name": "Alice", "address": {"city": "NYC"}}}
->
interface Root {
user: User;
}
interface User {
name: string;
address: Address;
}
interface Address {
city: string;
}Массив в readonly-кортеж
[{"id": 1}, {"id": 2}]
->
interface Item {
id: number;
}
type Root = readonly Item[];Часто задаваемые вопросы
Какие конструкции TypeScript он генерирует?
По умолчанию — interface, по одному на каждую форму объекта. Необязательные поля помечаются знаком ?. Массивы становятся T[]. Массивы со смешанными типами — объединением. Строки распознанных форматов (например, ISO-даты) остаются string, если только вы не включите branded-типы. Некоторые страницы предлагают type-алиасы вместо interface.
Как обрабатываются вложенные объекты?
Каждая отдельная вложенная форма получает собственный interface, названный по пути свойства (User, UserAddress, UserPreferences). Если два свойства имеют одинаковую форму, генератор может дедуплицировать или нет — в зависимости от настроек. Проверьте вывод и при необходимости объедините вручную.
Свойства обязательные или необязательные?
По умолчанию свойства, присутствующие в образце, помечаются обязательными. Свойства, встречающиеся в одних элементах массива, но не в других, помечаются необязательными через ?. Включите «все необязательные», если ваш образец — один пример из множества возможных форм.
Как обрабатываются null и undefined?
null в JSON становится null в TypeScript (не undefined). Свойство, которое иногда строка, а иногда null, становится string | null. В JSON нет undefined, поэтому генератор никогда не выводит undefined напрямую.
А как насчёт union-типов и размеченных объединений?
Когда массив содержит объекты разных форм, генератор выводит объединение интерфейсов. Он не определяет автоматически поле-дискриминатор; перепишите вручную в размеченное объединение (например, с тегом kind), если хотите исчерпывающее сужение типов.
Загружается ли JSON?
Нет. Преобразование выполняется в вашем браузере через JSON-парсер на JS и строковые шаблоны. Вставленный JSON не покидает ваше устройство.
Совпадёт ли результат с тем, что реально возвращает мой бэкенд?
Только настолько, насколько хорош образец. Всегда валидируйте данные в рантайме по схеме (Zod, io-ts, Yup) — TypeScript-типы стираются в рантайме и не поймают бэкенд, отошедший от примера.