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

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

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

Начать курс

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

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

Проблема стандартного JSON.parse

Рассмотрим типичный сценарий:

const jsonString = '{"name":"Alice","age":30}';
const user: any = JSON.parse(jsonString); // тип any
console.log(user.name.toUpperCase()); // Ошибка во время выполнения, если name отсутствует

TypeScript не предупредит вас, если структура JSON не соответствует ожидаемой. Решение — использовать утверждение типа (type assertion) или, что лучше, — валидацию во время выполнения.

Базовое утверждение типа (Type Assertion)

Самый простой способ — явно указать тип результата:

interface User {
  id: number;
  name: string;
  email?: string;
}

const raw = '{"id":1,"name":"Bob"}';
const user = JSON.parse(raw) as User;
console.log(user.name); // TypeScript знает, что это string

Минус: если JSON придет с другими полями, ошибка возникнет только в рантайме. Это небезопасно при работе с внешними API.

Рекурсивные и условные типы для JSON

TypeScript позволяет описать любой JSON через рекурсивный тип:

type JSONValue = 
  | string
  | number
  | boolean
  | null
  | JSONValue[]
  | { [key: string]: JSONValue };

function safeParse(json: string): JSONValue | Error {
  try {
    return JSON.parse(json) as JSONValue;
  } catch (e) {
    return new Error('Invalid JSON');
  }
}

Такой подход гарантирует, что результат всегда будет валидной JSON-структурой, но не проверяет конкретную форму.

Библиотека Zod — валидация схем во время выполнения

Zod — самая популярная библиотека для декларативной валидации данных в TypeScript. Она позволяет описать схему и получить тип из неё автоматически.

Установка

npm install zod

Пример использования

import { z } from 'zod';

// Описываем схему
const UserSchema = z.object({
  id: z.number().positive(),
  name: z.string().min(1),
  email: z.string().email().optional(),
  role: z.enum(['admin', 'user']).default('user'),
});

// Выводим тип из схемы
type User = z.infer<typeof UserSchema>;

// Безопасный парсинг
const result = UserSchema.safeParse(JSON.parse(rawJson));

if (result.success) {
  // result.data имеет тип User
  console.log(result.data.name);
} else {
  console.error(result.error.format());
}

Zod автоматически проверяет типы, обязательность полей, значения по умолчанию и возвращает подробные ошибки. Это идеальный выбор для обработки данных от REST API или конфигурационных файлов.

Библиотека io-ts — функциональный подход

io-ts основана на функциональном программировании и библиотеке fp-ts. Она использует композицию кодеков (codecs) для декодирования/кодирования данных.

Пример

import * as t from 'io-ts';
import { isRight } from 'fp-ts/lib/Either';

const UserCodec = t.type({
  id: t.number,
  name: t.string,
  tags: t.array(t.string),
});

const decoded = UserCodec.decode(JSON.parse(raw));

if (isRight(decoded)) {
  // decoded.right — типизированный объект
  console.log(decoded.right.name);
} else {
  // decoded.left — ошибки валидации
  console.log(decoded.left);
}

io-ts более строгий и математически корректный, но требует понимания функциональных концепций (Either, pipe).

Сериализация в JSON с TypeScript

Обратная задача — преобразовать объект в JSON-строку. Стандартный JSON.stringify() работает, но не учитывает типы TypeScript. Чтобы контролировать процесс, можно использовать метод toJSON() в классах:

class Product {
  constructor(
    public id: number,
    public name: string,
    private secretKey: string
  ) {}

  toJSON() {
    return {
      id: this.id,
      name: this.name,
      // secretKey не попадает в JSON
    };
  }
}

const product = new Product(1, 'Laptop', 'hidden123');
console.log(JSON.stringify(product)); // {"id":1,"name":"Laptop"}

Работа с JSON Schema

Если вы используете OpenAPI или JSON Schema для

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