Serialização de objetos em TypeScript: do JSON ao protobuf
Serialização é o processo de converter uma estrutura de dados complexa (objeto, array, instância de classe) em um formato adequado para armazenamento ou transmissão pela rede. O processo inverso — desserialização — restaura o objeto a partir desse formato. Em TypeScript, que é uma extensão estritamente tipada do JavaScript, a serialização ganha importância especial: é importante não apenas transmitir os dados, mas também preservar os tipos, métodos e a estrutura das classes.
Neste artigo, abordaremos as principais abordagens e ferramentas para serialização de objetos em TypeScript, desde recursos nativos até bibliotecas especializadas.
1. Serialização nativa: JSON.stringify e JSON.parse
A maneira mais simples e comum é usar os métodos nativos JSON.stringify() e JSON.parse(). No entanto, essa abordagem tem limitações:
- Não serializa funções,
undefined,Symbol,BigInt(em versões antigas). - Não preserva o protótipo do objeto — na desserialização, você obtém um objeto comum, não uma instância da classe.
- Referências cíclicas causam erro.
// Exemplo de serialização simplesinterface User { id: number; name: string; email: string;}
const user: User = { id: 1, name: "João", email: "joao@example.com"};
const jsonString = JSON.stringify(user);console.log(jsonString); // {"id":1,"name":"João","email":"joao@example.com"}
const parsedUser: User = JSON.parse(jsonString);console.log(parsedUser.name); // JoãoPara dados simples, isso é suficiente, mas se você precisar trabalhar com classes, será necessária uma solução mais avançada.
2. Serialização personalizada com métodos toJSON e fromJSON
TypeScript (e JavaScript) permite definir na classe o método toJSON(), que será chamado durante a serialização via JSON.stringify. Para desserialização, você pode criar um método estático fromJSON.
class Person { constructor( public firstName: string, public lastName: string, public age: number ) {}
// Método para serialização toJSON() { return { fullName: `${this.firstName} ${this.lastName}`, age: this.age }; }
// Método estático para desserialização static fromJSON(json: any): Person { const [firstName, lastName] = json.fullName.split(' '); return new Person(firstName, lastName, json.age); }}
const person = new Person("Ana", "Pereira", 30);const json = JSON.stringify(person);console.log(json); // {"fullName":"Ana Pereira","age":30}
const restoredPerson = Person.fromJSON(JSON.parse(json));console.log(restoredPerson.firstName); // AnaEssa abordagem oferece controle total, mas exige escrever código repetitivo para cada classe.
3. Biblioteca class-transformer
class-transformer é uma das bibliotecas mais populares para serialização/desserialização em TypeScript. Ela permite converter objetos comuns em instâncias de classe e vice-versa usando decoradores.
Instalação:
npm install class-transformer reflect-metadataExemplo de uso:
import { plainToClass, classToPlain, Expose, Transform } from "class-transformer";import "reflect-metadata";
class Product { @Expose() id: number;
@Expose() name: string;
@Expose() @Transform(({ value }) => value.toUpperCase()) // transformação personalizada category: string;
@Expose({ name: "price_with_tax" }) // renomeação de campo 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} (${th