Язык, на котором говорят API
API обмениваются данными в формате JSON — это текст вида {"id": 1, "name": "Ana"}. TypeScript не нуждается в библиотеке для этого: JSON.stringify превращает значение в JSON-текст, а JSON.parse превращает JSON-текст обратно в значение. Оба пришли из самого JavaScript.
interface описывает форму, которую вы ожидаете с любой стороны. Особого синтаксиса для переименования поля нет: ключ в JSON — это в точности то имя свойства, которое вы написали. Когда ключ должен называться иначе, вы переименовываете его вручную — либо при создании объекта, либо сразу после разбора.
От объекта к JSON
JSON.stringify(value) выдаёт компактный JSON для машин; JSON.stringify(value, null, 2) добавляет отступ в два пробела — для людей и для журналов.
Необязательное свойство (записанное как email?: string), которое так и не было задано, просто не попадает в JSON — пустой ключ не появляется.
Компактный и красивый JSON
У Ana нет адреса электронной почты, поэтому ключ email полностью отсутствует в её JSON. Полная запись Ben печатается с отступами.
Вывод: программа на TypeScript и захваченный вывод
interface UserRecord {
id: number
name: string
// Необязательное поле: когда его нет, JSON.stringify не включает этот ключ.
email?: string
}
const ana: UserRecord = { id: 1, name: "Ana" }
console.log(JSON.stringify(ana))
const ben: UserRecord = { id: 2, name: "Ben", email: "ben@example.com" }
console.log(JSON.stringify(ben, null, 2))
От JSON к объекту
JSON.parse возвращает разобранное значение, а as UserRecord сообщает проверщику типов, что именно вы ожидаете там найти. Некорректный JSON не возвращает значение-ошибку — он выбрасывает исключение, поэтому оберните вызов в try/catch.
Важно знать одно: неизвестные ключи не отбрасываются. JSON.parse сохраняет каждый ключ, который есть в тексте; интерфейс описывает лишь то, что вы обещаете использовать. Когда нужен чистый объект, скопируйте нужные вам поля.
Разбор и лишний ключ
JSON содержит ключ extra, о котором интерфейс ничего не говорит. Ничего не ломается — во время выполнения этот ключ действительно там есть, а копирование двух нужных полей даёт чистый { id: 7, name: 'Cleo' }. Испорченный JSON выбрасывает исключение, и catch печатает сообщение.
Вывод: программа на TypeScript и захваченный вывод
interface UserRecord {
id: number
name: string
}
const text = '{"id": 7, "name": "Cleo", "extra": "ignored"}'
// JSON.parse сохраняет каждый найденный ключ — «as UserRecord» это лишь обещание
// проверщику типов, а не фильтр во время выполнения.
const parsed = JSON.parse(text) as UserRecord
console.log("разобрано:", parsed)
// Скопируйте те поля, которые вы действительно ожидаете, и лишнее исчезнет.
const user: UserRecord = { id: parsed.id, name: parsed.name }
console.log("объект: ", user)
// Испорченный JSON выбрасывает исключение вместо возврата значения-ошибки.
try {
JSON.parse('{"id": ')
} catch (err) {
console.log("ошибка: ", (err as Error).message)
}
Вложенные данные
Настоящие данные API вложены друг в друга: заказ несёт своего пользователя и список товаров. Объекты внутри объектов и массивы автоматически превращаются в JSON-объекты и JSON-массивы — особая обработка не нужна.
Заказ с пользователем внутри
Вложенный объект user становится вложенным JSON-объектом, массив items становится JSON-массивом — форма данных и есть форма JSON.
Вывод: программа на TypeScript и захваченный вывод
interface UserRecord {
id: number
name: string
}
interface OrderRecord {
id: number
items: string[]
user: UserRecord
}
const order: OrderRecord = {
id: 1042,
items: ["клавиатура", "мышь"],
user: { id: 1, name: "Ana" },
}
console.log(JSON.stringify(order, null, 2))