Object Serialization in TypeScript: Libraries, Methods, and Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Object Serialization in TypeScript: A Complete Guide



Serialization is the process of converting an object into a byte stream or string for transmission over a network or storage. In TypeScript, this task is complicated by the need to preserve types, support polymorphism, and work with classes. Let's look at the main tools and approaches.



1. Built-in Serialization: JSON.stringify / JSON.parse



The basic mechanism in JavaScript/TypeScript is the global JSON object. It only serializes simple types: strings, numbers, booleans, arrays, and flat objects. Methods, symbols, undefined, Date, and class instances are lost.



// Example: class serializationclass User {  constructor(    public name: string,    private password: string,    public createdAt: Date = new Date()  ) {}}

const user = new User('Alice', 'secret123');const json = JSON.stringify(user);// Result: {"name":"Alice","createdAt":"2025-03-24T10:00:00.000Z"}// password is not included in JSON (private), but Date becomes a string// During deserialization, we get a plain object, not a User instance

const parsed: User = JSON.parse(json) as User;console.log(parsed instanceof User); // false


Problems:

  • Type loss (a class instance becomes an object).
  • Private fields, methods, and getters are not serialized.
  • Dates, Map, Set, BigInt require manual conversion.
  • Polymorphism is not supported — you need to manually restore the type.


2. The class-transformer Library



class-transformer is the most popular solution for serializing/deserializing classes in TypeScript. It uses decorators to describe transformation rules.



Installation

npm install class-transformer reflect-metadata


Usage Example

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) // nested transformation address!: Address;

@Expose() @Transform(({ value }) => new Date(value)) // custom transformation hireDate!: Date;

// Method is not serialized get displayName(): string { return `${this.name} (ID: ${this.id})`; }}

// Deserialization from plain objectconst 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); // trueconsole.log(employee.hireDate instanceof Date); // true

// Serialization backconst plain = classToPlain(employee);console.log(plain); // { id: 1, name: 'Bob', address: { city: 'Moscow', street: 'Tverskaya' }, hireDate: '2024-01-15T00:00:00.000Z' }


Advantages:

  • Automatic type restoration (nested objects, arrays).
  • Polymorphism support via @Type with a discriminator.
  • Value transformation (dates, numbers, custom formats).
  • Works with private fields via @Expose.


Disadvantages:

  • Dependency on decorators (requires experimentalDecorators in tsconfig).
  • Not suitable for high-load systems (reflection slows down performance).
  • Bundle size ~15KB (gzip).


3. Protocol Buffers with protobuf-ts



For microservice architecture and gRPC, Protocol Buffers are often used. The TypeScript implementation protobuf-ts generates typed

Recommendations