Сериализация объектов в TypeScript: от JSON до protobuf
Сериализация — это процесс преобразования сложной структуры данных (объекта, массива, экземпляра класса) в формат, пригодный для хранения или передачи по сети. Обратный процесс — десериализация — восстанавливает объект из этого формата. В TypeScript, который является строго типизированной надстройкой над JavaScript, сериализация приобретает особое значение: важно не только передать данные, но и сохранить типы, методы и структуру классов.
В этой статье мы рассмотрим основные подходы и инструменты для сериализации объектов в TypeScript, от встроенных средств до специализированных библиотек.
1. Нативная сериализация: JSON.stringify и JSON.parse
Самый простой и распространённый способ — использование встроенных методов JSON.stringify() и JSON.parse(). Однако у этого подхода есть ограничения:
- Не сериализуются функции,
undefined,Symbol,BigInt(в старых версиях). - Не сохраняется прототип объекта — при десериализации вы получите обычный объект, а не экземпляр класса.
- Циклические ссылки вызывают ошибку.
// Пример простой сериализации
interface User {
id: number;
name: string;
email: string;
}
const user: User = {
id: 1,
name: "Иван",
email: "ivan@example.com"
};
const jsonString = JSON.stringify(user);
console.log(jsonString); // {"id":1,"name":"Иван","email":"ivan@example.com"}
const parsedUser: User = JSON.parse(jsonString);
console.log(parsedUser.name); // Иван
Для простых данных этого достаточно, но если вам нужно работать с классами, потребуется более продвинутое решение.
2. Кастомная сериализация с методами toJSON и fromJSON
TypeScript (и JavaScript) позволяет определить в классе метод toJSON(), который будет вызываться при сериализации через JSON.stringify. Для десериализации можно создать статический метод fromJSON.
class Person {
constructor(
public firstName: string,
public lastName: string,
public age: number
) {}
// Метод для сериализации
toJSON() {
return {
fullName: `${this.firstName} ${this.lastName}`,
age: this.age
};
}
// Статический метод для десериализации
static fromJSON(json: any): Person {
const [firstName, lastName] = json.fullName.split(' ');
return new Person(firstName, lastName, json.age);
}
}
const person = new Person("Анна", "Петрова", 30);
const json = JSON.stringify(person);
console.log(json); // {"fullName":"Анна Петрова","age":30}
const restoredPerson = Person.fromJSON(JSON.parse(json));
console.log(restoredPerson.firstName); // Анна
Этот подход даёт полный контроль, но требует написания шаблонного кода для каждого класса.
3. Библиотека class-transformer
class-transformer — одна из самых популярных библиотек для сериализации/десериализации в TypeScript. Она позволяет преобразовывать обычные объекты в экземпляры классов и обратно с помощью декораторов.
Установка:
npm install class-transformer reflect-metadata
Пример использования:
import { plainToClass, classToPlain, Expose, Transform } from "class-transformer";
import "reflect-metadata";
class Product {
@Expose()
id: number;
@Expose()
name: string;
@Expose()
@Transform(({ value }) => value.toUpperCase()) // кастомное преобразование
category: string;
@Expose({ name: "price_with_tax" }) // переименование поля
price: number;
constructor(id: number, name: string, category: string, price: number) {
this.id = id;
this.name = name;
this.category = category;
this.price = price;
}
getInfo(): string {
return `${this.name} (${this.category}) - ${this.price} руб.`;
}
}
// Десериализация
const plainProduct = {
id: 1,
name: "Ноутбук",
category: "электроника",
price_with_tax: 75000
};
const productInstance = plainToClass(Product, plainProduct);
console.log(productInstance.getInfo()); // Ноутбук (ЭЛЕКТРОНИКА) - 75000 руб.
// Сериализация
const serialized = classToPlain(productInstance, { excludeExtraneousValues: true });
console.log(serialized);
// { id: 1, name: 'Ноутбук', category: 'ЭЛЕКТРОНИКА', price_with_tax: 75000 }
Ключевые возможности:
- Декораторы:
@Expose(включает поле),@Exclude(исключает),@Transform(кастомное преобразование),@Type(указывает тип для вложенных объектов). - Поддержка вложенных объектов и