Сериализация объектов в TypeScript: полное руководство
Сериализация — процесс преобразования объекта в поток байтов или строку для передачи по сети или сохранения. В TypeScript эта задача усложняется необходимостью сохранять типы, поддерживать полиморфизм и работать с классами. Рассмотрим основные инструменты и подходы.
1. Встроенная сериализация: JSON.stringify / JSON.parse
Базовый механизм в JavaScript/TypeScript — глобальный объект JSON. Он сериализует только простые типы: строки, числа, булевы значения, массивы и плоские объекты. Методы, символы, undefined, Date и экземпляры классов — теряются.
// Пример: сериализация класса
class User {
constructor(
public name: string,
private password: string,
public createdAt: Date = new Date()
) {}
}
const user = new User('Alice', 'secret123');
const json = JSON.stringify(user);
// Результат: {"name":"Alice","createdAt":"2025-03-24T10:00:00.000Z"}
// password не попал в JSON (private), но Date стал строкой
// При десериализации мы получим обычный объект, не экземпляр User
const parsed: User = JSON.parse(json) as User;
console.log(parsed instanceof User); // false
Проблемы:
- Потеря типа (экземпляр класса превращается в
object). - Не сериализуются приватные поля, методы, геттеры.
- Даты, Map, Set, BigInt требуют ручного преобразования.
- Полиморфизм не поддерживается — нужно вручную восстанавливать тип.
2. Библиотека class-transformer
class-transformer — наиболее популярное решение для сериализации/десериализации классов в TypeScript. Она использует декораторы для описания правил преобразования.
Установка
npm install class-transformer reflect-metadata
Пример использования
import { plainToClass, classToPlain, Expose, Transform, Type } from 'class-transformer';
import 'reflect-metadata';
class Address {
@Expose()
city!: string;
@Expose()
street!: string;
}
class Employee {
@Expose()
id!: number;
@Expose()
name!: string;
@Expose()
@Type(() => Address) // вложенная трансформация
address!: Address;
@Expose()
@Transform(({ value }) => new Date(value)) // кастомное преобразование
hireDate!: Date;
// Метод не сериализуется
get displayName(): string {
return `${this.name} (ID: ${this.id})`;
}
}
// Десериализация из plain object
const plainData = {
id: 1,
name: 'Bob',
address: { city: 'Moscow', street: 'Tverskaya' },
hireDate: '2024-01-15T00:00:00.000Z'
};
const employee = plainToClass(Employee, plainData);
console.log(employee instanceof Employee); // true
console.log(employee.hireDate instanceof Date); // true
// Сериализация обратно
const plain = classToPlain(employee);
console.log(plain); // { id: 1, name: 'Bob', address: { city: 'Moscow', street: 'Tverskaya' }, hireDate: '2024-01-15T00:00:00.000Z' }
Преимущества:
- Автоматическое восстановление типов (вложенные объекты, массивы).
- Поддержка полиморфизма через
@Typeс дискриминатором. - Трансформация значений (даты, числа, кастомные форматы).
- Работа с приватными полями через
@Expose.
Недостатки:
- Зависимость от декораторов (требуется
experimentalDecoratorsв tsconfig). - Не подходит для высоконагруженных систем (рефлексия замедляет работу).
- Размер бандла ~15KB (gzip).
3. Протокол буферы (Protocol Buffers) с protobuf-ts
Для микросервисной архитектуры и gRPC часто используют Protocol Buffers. TypeScript-реализация protobuf-ts генерирует типизированный код из .proto файлов.
Пример .proto файла
syntax = "proto3";
message UserProto {
int32 id = 1;
string name = 2;
string email = 3;
google.protobuf.Timestamp created_at = 4;
}
Использование в TypeScript
import { UserProto } from './generated/user';
import { Timestamp } from './generated/google/protobuf/timestamp';
const user = User Также в библиотеке
Moment.js / Day.js для JavaScript (Node.js): полное руководство с примерами
JWT токены в Kotlin: генерация, проверка и использование с io.jsonwebtoken
Работа с XML в Java: DOM, SAX, StAX и JAXB
Кэширование в C++: Redis, memcached, LevelDB и другие инструменты
Работа с XML в Go (Golang): пакет encoding/xml и альтернативы