Типы TypeScript из JSON — как делать правильно
Генерация типов из примера ответа занимает секунды. А вот типы, которым можно доверять, требуют чуть больше решений: что необязательно, что может быть null, как назвать сущности и как убедиться, что API держит обещания во время выполнения.
Начните с реальных примеров
Вставьте ответ в конвертер JSON в TypeScript, и вы получите интерфейсы для каждого вложенного объекта. Но один пример описывает только одну структуру, поэтому вставляйте массив из нескольких реальных объектов: конвертер объединит их и пометит как необязательные поля, которых нет в некоторых из них.
[
{ "id": 1, "name": "Ada", "email": "ada@example.com", "team": { "id": 7, "name": "Core" } },
{ "id": 2, "name": "Grace", "email": null }
]
interface User {
id: number;
name: string;
email: string | null;
team?: Team;
}
interface Team {
id: number;
name: string;
}
Необязательное не значит nullable
team?: Team означает, что ключ может отсутствовать. email: string | null означает, что ключ всегда есть, но может содержать null. API используют их по-разному, и в коде проверяются они тоже по-разному ('team' in user и user.email === null), поэтому сохраняйте различие, а не превращайте всё в ?: … | null.
Уточните то, что пример не может показать
- Литеральные объединения — поле
status, которое в примере равно"active", станетstring; замените его на'active' | 'paused' | 'deleted'из документации API. - Даты приходят как строки ISO. Типизируйте их как
stringи разбирайте на границе приложения — не притворяйтесь, что это объектыDate. - ID — большие числовые ID (больше 253) теряют точность в JavaScript, поэтому многие API по этой причине отдают их строками.
- Пустые массивы становятся
unknown[]илиany[]; тип элементов укажите сами.
Во время выполнения типов нет
TypeScript проверяет ваш код, а не данные. Если API изменится, компилятор этого не заметит. Проверяйте ответы на границе:
- Создайте схему по тем же примерам с помощью JSON в JSON Schema.
- Отредактируйте её — обязательные поля, перечисления, форматы вроде
date-time— и проверьте реальные данные в JSON Schema Validator. - Проверяйте данные в приложении с помощью библиотеки, например Ajv, и генерируйте типы из схемы (JSON Schema в TypeScript), чтобы был один источник истины.
import Ajv from 'ajv';
const ajv = new Ajv();
const validate = ajv.compile(userSchema);
const data = await res.json();
if (!validate(data)) throw new Error('Unexpected API response: ' + ajv.errorsText(validate.errors));
Библиотеки вроде Zod или Valibot делают то же самое, но схема пишется на самом TypeScript, а тип выводится из неё.
Именование и структура
Давайте корневому типу осмысленное имя (User, а не Root), экспортируйте типы из одного модуля и используйте interface для объектов, которые, возможно, понадобится расширять. Сначала отформатируйте большие ответы в JSON Formatter, чтобы увидеть, какие ветки важны.