Введение
JSON (JavaScript Object Notation) — это легкий формат обмена данными, который широко используется в веб-разработке для передачи информации между клиентом и сервером. TypeScript, будучи строго типизированным надмножеством JavaScript, предоставляет мощные инструменты для безопасной и удобной работы с JSON. В этой статье мы подробно рассмотрим, как выполнять парсинг и сериализацию JSON в TypeScript, использовать типы для обеспечения корректности данных и избегать типичных ошибок.
Правильная работа с JSON критически важна для создания надежных и масштабируемых приложений. TypeScript позволяет не только преобразовывать строки JSON в объекты и обратно, но и гарантировать, что структура и типы данных соответствуют ожидаемым. Это особенно полезно при работе с API, конфигурационными файлами и базами данных.
Основы парсинга JSON в TypeScript
Парсинг JSON — это процесс преобразования строки JSON в объект TypeScript. Для этого используется глобальный метод JSON.parse(). Однако, в отличие от JavaScript, в TypeScript мы можем указать ожидаемый тип результата, что делает код более предсказуемым.
Простой парсинг без типов
Базовый пример парсинга JSON строки:
const jsonString = '{"name": "Анна", "age": 30, "city": "Москва"}';
const user = JSON.parse(jsonString);
console.log(user.name); // "Анна"
В этом случае TypeScript выведет тип any для переменной user, что снижает безопасность типов. Лучше использовать явное указание типа.
Парсинг с указанием типа через интерфейс
Наиболее правильный подход — определить интерфейс и использовать его при парсинге:
interface User {
name: string;
age: number;
city: string;
}
const jsonString = '{"name": "Анна", "age": 30, "city": "Москва"}';
const user: User = JSON.parse(jsonString);
console.log(user.name); // TypeScript знает, что это string
Этот подход позволяет IDE предоставлять автодополнение и проверять типы на этапе компиляции.
Обработка ошибок парсинга
JSON строки могут быть некорректными, поэтому важно обрабатывать исключения:
function safeParseJSON<T>(json: string): T | null {
try {
return JSON.parse(json) as T;
} catch (error) {
console.error('Ошибка парсинга JSON:', error);
return null;
}
}
const invalidJson = '{"name": "Анна", age: 30}'; // Некорректный JSON
const result = safeParseJSON<User>(invalidJson);
if (result) {
console.log(result.name);
} else {
console.log('Не удалось распарсить JSON');
}
Функция safeParseJSON принимает дженерик-параметр, что позволяет переиспользовать её для разных типов данных.
Сериализация объектов в JSON
Сериализация — обратный процесс преобразования объекта TypeScript в строку JSON. Для этого используется метод JSON.stringify(). TypeScript не добавляет новых возможностей к этому методу, но помогает контролировать, какие данные попадают в итоговую строку.
Базовая сериализация
const user: User = {
name: "Иван",
age: 25,
city: "Санкт-Петербург"
};
const jsonString = JSON.stringify(user);
console.log(jsonString); // {"name":"Иван","age":25,"city":"Санкт-Петербург"}
Использование replacer для фильтрации полей
Второй параметр JSON.stringify() — функция replacer, которая позволяет контролировать, какие поля включать в результат:
const jsonStringFiltered = JSON.stringify(user, (key, value) => {
if (key === 'age') {
return undefined; // Исключаем поле age
}
return value;
});
console.log(jsonStringFiltered); // {"name":"Иван","city":"Санкт-Петербург"}
Это полезно, когда нужно скрыть чувствительные данные или сократить размер передаваемой информации.
Форматирование с помощью space
Третий параметр позволяет добавить отступы для читаемости:
const prettyJson = JSON.stringify(user, null, 2);
console.log(prettyJson);
// {
// "name": "Иван",
// "age": 25,
// "city": "Санкт-Петербург"
// }
Параметр 2 означает отступ в 2 пробела. Можно также использовать строку, например "\t" для табуляции.
Типизация JSON с помощью интерфейсов и дженериков
TypeScript позволяет создавать сложные типы для JSON структур, что особенно важно при работе с вложенными данными и массивами.
Вложенные объекты и массивы
interface Address {
street: string;
city: string;
zipCode: string;
}
interface Company {
name: string;
employees: User[];
address: Address;
}
const companyJson = `{
"name": "TechCorp",
"employees": [
{"name": "Ольга", "age": 28, "city": "Москва"},
{"name": "Петр", "age": 35, "city": "Казань"}
],
"address": {
"street": "Ленина, 10",
"city": "Москва",
"zipCode": "101000"
}
}`;
const company: Company = JSON.parse(companyJson);
console.log(company.employees[0].name); // "Ольга"
Использование дженериков для универсальных функций
Дженерики позволяют создавать переиспользуемые функции для работы с JSON:
async function fetchJSON<T>(url: string): Promise<T> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data: T = await response.json();
return data;
}
// Использование
interface ApiResponse {
status: string;
data: User[];
}
const users = await fetchJSON<ApiResponse>('/api/users');
console.log(users.data); // TypeScript знает, что это User[]
Такой подход делает код типобезопасным и легко поддерживаемым.
Проверка типов во время выполнения
TypeScript проверяет типы только на этапе компиляции. Для runtime-валидации JSON данных можно использовать сторонние библиотеки или написать свою функцию проверки:
function isUser(obj: any): obj is User {
return (
typeof obj.name === 'string' &&
typeof obj.age === 'number' &&
typeof obj.city ===