Using Decorators to Serialize Entities in TypeScript
Serialization turns objects into formats like JSON so they can be stored, sent over the network, or logged safely. TypeScript decorators make this process much cleaner by allowing you to annotate which properties should or should not be serialized.
In this howto, you’ll build a fully working serialization system using decorators — step by step and with clean, modern TypeScript patterns.
Step 1: Enable Decorators in TypeScript
Decorators are still experimental, so you must explicitly enable them.
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}Install TypeScript if needed:
npm install typescript --save-devStep 2: What Decorators Do
Decorators let you attach metadata or behavior to:
- classes
- properties
- methods
- parameters
In serialization, they help you mark which properties should be included.
Step 3: Creating a Serializable Property Decorator
Here’s a minimal decorator that records which properties should be serialized:
function Serializable(target: any, key: string) {
if (!target.constructor.serializableProperties) {
target.constructor.serializableProperties = [];
}
target.constructor.serializableProperties.push(key);
}This attaches an array serializableProperties to the class constructor.
Step 4: Applying the Decorator to an Entity
class User {
@Serializable
firstName: string;
@Serializable
lastName: string;
password: string; // sensitive, excluded
constructor(firstName: string, lastName: string, password: string) {
this.firstName = firstName;
this.lastName = lastName;
this.password = password;
}
}Only decorated properties will be serialized.
Step 5: Implementing the Serialization Logic
function serialize(instance: any): string {
const output: any = {};
const props = instance.constructor.serializableProperties || [];
for (const key of props) {
output[key] = instance[key];
}
return JSON.stringify(output);
}Step 6: Serializing an Entity
const user = new User('John', 'Doe', 'secretPassword');
console.log(serialize(user));
// {"firstName":"John","lastName":"Doe"}The password field is ignored — exactly what we want.
Step 7: Adding More Power — Aliases and Metadata
A more advanced decorator allows renaming fields in output:
function Serializable(alias?: string) {
return (target: any, key: string) => {
if (!target.constructor.serializableProperties) {
target.constructor.serializableProperties = [];
}
target.constructor.serializableProperties.push({
key,
alias: alias || key,
});
};
}Usage:
class User {
@Serializable('first_name')
firstName: string;
@Serializable('last_name')
lastName: string;
password: string;
}Updated serialization:
const u = new User('John', 'Doe', 'secretPassword');
console.log(serialize(u));
// {"first_name":"John","last_name":"Doe"}Conclusion
Decorators are a clean, expressive way to control how TypeScript entities are serialized.
With this pattern you can:
- mark safe properties
- hide sensitive data
- rename fields for APIs
- extend serialization rules
- support nested objects with custom logic
This makes your data structures more predictable, secure, and maintainable—especially in large-scale apps where consistency matters.
If you’d like, I can expand this into:
- a Deep Serialization System (nested + typed)
- a version for backend frameworks (NestJS, Express, tRPC)
- a more advanced
.mdxdemo with real-world entity patterns