JSON обработка в TypeScript: типизация, валидация и парсинг

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

JSON обработка в TypeScript: от базовых операций до продвинутой типизации

JSON (JavaScript Object Notation) остаётся основным форматом обмена данными в веб-разработке. TypeScript добавляет к работе с JSON мощную систему типов, которая позволяет избежать множества ошибок на этапе компиляции. В этой статье мы разберём все аспекты обработки JSON в TypeScript: от простого парсинга до создания строго типизированных валидаторов.

Базовый парсинг и сериализация

Начнём с фундаментальных операций. Встроенные методы JSON.parse() и JSON.stringify() работают в TypeScript так же, как в JavaScript, но с важными отличиями в типизации.

// Простой парсинг — результат будет any
const data: any = JSON.parse('{"name": "Alice", "age": 30}');

// Лучше сразу указать тип
interface User {
  name: string;
  age: number;
}

const user: User = JSON.parse('{"name": "Alice", "age": 30}') as User;
console.log(user.name); // Alice

Важно понимать: as User — это приведение типа (type assertion), а не проверка. Если JSON содержит невалидные данные, TypeScript не предупредит вас об ошибке. Для безопасной работы нужна валидация.

Безопасный парсинг с помощью Generics

Создадим универсальную функцию для безопасного парсинга JSON с проверкой структуры:

function safeParse<T>(json: string, validator: (data: unknown) => data is T): T | null {
  try {
    const parsed: unknown = JSON.parse(json);
    if (validator(parsed)) {
      return parsed;
    }
    return null;
  } catch {
    return null;
  }
}

// Определяем тип и функцию-валидатор
interface Product {
  id: number;
  title: string;
  price: number;
}

function isProduct(data: unknown): data is Product {
  if (typeof data !== 'object' || data === null) return false;
  const obj = data as Record<string, unknown>;
  return (
    typeof obj.id === 'number' &&
    typeof obj.title === 'string' &&
    typeof obj.price === 'number'
  );
}

const jsonString = '{"id": 1, "title": "Book", "price": 19.99}';
const product = safeParse<Product>(jsonString, isProduct);
if (product) {
  console.log(`Товар: ${product.title}, цена: ${product.price}`);
} else {
  console.log('Неверный формат JSON');
}

Работа с вложенными структурами и массивами

Реальные JSON-данные часто содержат вложенные объекты и массивы. Рассмотрим пример с типизацией сложной структуры:

interface Order {
  id: string;
  customer: {
    name: string;
    email: string;
  };
  items: Array<{
    productId: number;
    quantity: number;
  }>;
  total: number;
}

// Парсим и сразу проверяем структуру
function parseOrder(json: string): Order {
  const raw = JSON.parse(json);
  
  // Простейшая проверка
  if (!raw.id || !raw.customer || !Array.isArray(raw.items)) {
    throw new Error('Invalid order structure');
  }
  
  return raw as Order;
}

const orderJson = `{
  "id": "ORD-001",
  "customer": {"name": "Bob", "email": "bob@example.com"},
  "items": [{"productId": 42, "quantity": 2}],
  "total": 59.98
}`;

try {
  const order = parseOrder(orderJson);
  console.log(`Заказ ${order.id} на сумму ${order.total}`);
} catch (e) {
  console.error('Ошибка парсинга:', e.message);
}

Сериализация с кастомными преобразователями

Иногда нужно контролировать, как объекты преобразуются в JSON. TypeScript позволяет создавать кастомные сериализаторы:

interface Config {
  host: string;
  port: number;
  timeout: number; // в миллисекундах
}

function serializeConfig(config: Config): string {
  return JSON.stringify({
    host: config.host,
    port: config.port,
    timeout: config.timeout / 1000 // конвертируем в секунды
  }, null, 2); // форматирование с отступами
}

const myConfig: Config = {
  host: 'localhost',
  port: 3000,
  timeout: 5000
};

console.log(serializeConfig(myConfig));
// Вывод:
// {
//   "host": "localhost",
//   "port": 3000,
//   "timeout": 5
// }

Продвинутая валидация с библиотеками

Для сложных проектов стоит рассмотреть специализированные библиотеки валидации. Две популярные опции:

  • Zod — современная библиотека с декларативным синтаксисом и отличной интеграцией с TypeScript
  • Yup — проверенная временем библиотека, часто используется с Formik

Пример с Zod:

import { z } from 'zod';

// Определяем схему валидации
const                    

Рекомендаций