Skip to Content
DocumentationDeclarative SerializationIntroduction

Declarative Serialization

In this section, we will explore how to use Codables to easily define complex and nested, serializable classes with minimal boilerplate.

The Problem

Often, when working with complex data, you need to maintain two formats:

  1. The actual Class instances, with all their properties and methods,
  2. Some kind of representation of them that is suitable for serialization, saving to a file, sending over the network, etc.

Then, you often need some kind of conversion logic to convert between the two formats.

Codables offers set of tools and conventions to help you avoid the entire “data format” and automatically handle serialization of your “core” classes.

What it means it is declarative? You define “what to serialize”, not “how to serialize it”.

Example

Let’s define some classes and mark them as codable:

import { codableClass, codable, Coder } from "codables"; @codableClass("Player") class Player { @codable() name: string; @codable() score: number; constructor(data: Pick<Player, "name" | "score">) { this.name = data.name; this.score = data.score; } } @codableClass("GameState") class GameState { @codable() players: Set<Player> = new Set(); @codable() createdAt = new Date(); @codable() activePlayer: Player | null = null; addPlayer(player: Player) { this.players.add(player); this.activePlayer = player; } }

That’s it! No separate interfaces, no conversion logic. No, “Set to array, then back to Set”, etc.

We can now create a Coder instance that is aware of our classes:

const coder = new Coder([GameState]); const gameState = new GameState(); gameState.addPlayer(new Player({ name: "Alice", score: 100 })); // Serialize directly const encoded = coder.encode(gameState); // Deserialize back to your classes const decoded = coder.decode<GameState>(encoded);

Key Benefits

  • Single source of truth: Your classes define both runtime behavior and serialization format
  • Type safety: Full TypeScript support with compile-time checking
  • Zero boilerplate: No manual conversion logic or separate data interfaces
  • Automatic handling: Complex types (Date, Set, Map) work seamlessly, even if deeply nested
  • Reference preservation: Object identity and circular references maintained

Only properties marked with @codable() are serialized. Every other property is ignored during serialization.

Last updated on