TypeScript JSON Serializer
typescript-json-serializer is a TypeScript library designed to facilitate the conversion between JavaScript/JSON objects and strongly-typed TypeScript classes. It leverages TypeScript decorators (`@JsonObject`, `@JsonProperty`) to define the serialization and deserialization mapping, allowing for complex nested structures, inheritance, and custom property transformations. The current stable version is 6.0.1, with a consistent release cadence that includes multiple major versions (v4, v5, v6) over a short period, indicating active maintenance and ongoing development. Its key differentiator lies in its declarative, decorator-driven approach, which provides a robust way to manage serialization logic directly within class definitions, including explicit support for enums, dates, and custom type resolvers. It also offers flexible configuration options for error handling, nullish value policies, and property name formatting, distinguishing it from simpler `JSON.parse`/`JSON.stringify` methods or libraries that rely purely on reflection without explicit decorator metadata.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'constructor')
cause This error frequently occurs when TypeScript's `emitDecoratorMetadata` compiler option is not enabled, preventing the serializer from inferring types at runtime, especially when dealing with nested objects or arrays.fixEnsure `emitDecoratorMetadata` and `experimentalDecorators` are set to `true` in your `tsconfig.json` file. -
Property 'propertyName' is not deserialized/serialized correctly or is missing.
cause The property either lacks the `@JsonProperty()` decorator, the class itself isn't decorated with `@JsonObject()`, or a custom `name` mapping in `@JsonProperty({ name: 'jsonKey' })` is incorrect.fixVerify that all classes intended for serialization are decorated with `@JsonObject()` and all properties needing to be serialized/deserialized have the `@JsonProperty()` decorator. Check `name` mappings if the JSON key differs from the class property name. -
Error: Deserialization error: Required property 'propertyName' is missing.
cause This typically happens when a JSON payload is missing a property that has been marked as `required: true` in its `@JsonProperty` decorator configuration.fixEnsure that the incoming JSON data contains all properties marked as `required: true`. Alternatively, adjust the `required` setting in `@JsonProperty` if the property is not strictly mandatory.
Warnings
- breaking Major version updates (e.g., v4.x to v5.x, v5.x to v6.x) often introduce breaking changes. Always review the release notes for specific changes, API adjustments, and migration guides when upgrading across major versions to avoid unexpected behavior.
- gotcha This library heavily relies on TypeScript's experimental decorator features. You MUST enable `experimentalDecorators` and `emitDecoratorMetadata` in your `tsconfig.json` compiler options for the decorators to function correctly at runtime. Failure to do so will lead to runtime errors during serialization or deserialization.
- gotcha For properties that are complex objects or arrays of complex objects, you often need to explicitly specify the type within the `@JsonProperty` decorator using the `type` option (e.g., `{type: MyClass}` or for arrays `{type: () => MyClass}` for circular dependencies) to ensure correct recursive deserialization.
Install
-
npm install typescript-json-serializer -
yarn add typescript-json-serializer -
pnpm add typescript-json-serializer
Imports
- JsonSerializer
import JsonSerializer from 'typescript-json-serializer';
import { JsonSerializer } from 'typescript-json-serializer'; - JsonObject
const { JsonObject } = require('typescript-json-serializer');import { JsonObject } from 'typescript-json-serializer'; - JsonProperty
const JsonProperty = require('typescript-json-serializer').JsonProperty;import { JsonProperty } from 'typescript-json-serializer'; - throwError
import * as serializer from 'typescript-json-serializer'; const errorCb = serializer.throwError;
import { throwError } from 'typescript-json-serializer';
Quickstart
import { JsonSerializer, JsonObject, JsonProperty, throwError } from 'typescript-json-serializer';
// 1. Define your classes using decorators
@JsonObject()
export class PhoneNumber {
@JsonProperty() countryCode: string;
@JsonProperty() value: string;
}
@JsonObject()
export class Person {
@JsonProperty({required: true}) id: number;
@JsonProperty() name: string;
@JsonProperty({name: 'dob'}) birthDate: Date;
@JsonProperty({type: PhoneNumber}) phone: PhoneNumber;
}
// 2. Prepare data (e.g., from an API response)
const jsonPayload = {
id: 123,
name: 'John Doe',
dob: '1990-05-15T00:00:00.000Z',
phone: {
countryCode: '+1',
value: '555-1234'
}
};
// 3. Instantiate the serializer
const serializer = new JsonSerializer({
errorCallback: throwError,
nullishPolicy: {
undefined: 'allow',
null: 'allow'
},
additionalPropertiesPolicy: 'disallow'
});
// 4. Deserialize JSON to a class instance
try {
const personInstance = serializer.deserialize(jsonPayload, Person);
console.log('Deserialized Person:', personInstance);
console.log('Person name:', personInstance.name); // Access as a class instance
console.log('Person phone country code:', personInstance.phone.countryCode);
// 5. Serialize a class instance back to JSON
const serializedJson = serializer.serialize(personInstance);
console.log('Serialized JSON:', serializedJson);
} catch (error) {
console.error('Serialization/Deserialization Error:', error);
}
// Ensure your tsconfig.json has:
// {
// "compilerOptions": {
// "emitDecoratorMetadata": true,
// "experimentalDecorators": true
// }
// }