o7planning

Parsing JSON in TypeScript with the json2typescript library

  1. json2typescript
  2. Install
  3. Basic example
  4. @JsonProperty
  5. @JsonConverter

1. json2typescript

json2typescript is a library that contains helper classes to define a mapping between a JSON document and a TypeScript object. This library is inspired by Java Jackson and has similar features.
Basically, json2typescript is suitable for large projects that require a few configuration steps. If you are only working with JSON in a small TypeScript project, consider using the JSON.parse(..) and JSON.stringify(..) methods, which are simple and do not require any additional configuration.

2. Install

First, install the json2typescript library into the project:
npm install json2typescript
Next, add the following properties to the tsconfig.json file:
tsconfig.json
{
  "compilerOptions": {  
    ...
    "experimentalDecorators": true,
    "allowJs": true
  }
}

3. Basic example

In this example, we will create 2 model files:
  • model_file1.ts
  • model_file2.ts.
Classes are defined in the model files. Use @JsonObject and @JsonProperty to annotate on the class and its properties to suggest to the tool how to convert TypeScript objects to JSON text and vice versa.
@JsonObject
A class is annotated with @JsonObject, then its object can be converted to a JSON text and vice versa.
@JsonProperty
A property of a TypeScript object can be converted to a property of JSON if it is annotated by @JsonProperty. Otherwise, it will be ignored.
All properties of the TypeScript class annotated by @JsonProperty must be set to default values. Otherwise, the result may not be what you expect.
model_file1.ts
import {
    JsonObject, JsonProperty, JsonConvert, OperationMode,
    ValueCheckingMode, PropertyConvertingMode
} from "json2typescript";

@JsonObject("Contact")
export class Contact {
    // PropertyConvertingMode.MAP_NULLABLE is default.
    // MAP_NULLABLE: Throw Exception if JSON value is undefined
    // IGNORE_NULLABLE: Using Java property default value if JSON value is undefined
    // PASS_NULLABLE: Set Java property value to null if JSON value is undefined
    @JsonProperty("address", String, PropertyConvertingMode.MAP_NULLABLE)
    address: string = '';
    @JsonProperty("phone", String, PropertyConvertingMode.MAP_NULLABLE)
    phone: string = '';
}
@JsonObject("Employee")
export class Employee {
    @JsonProperty("employeeName", String, PropertyConvertingMode.MAP_NULLABLE)
    name: string = '';
    @JsonProperty("email", String, PropertyConvertingMode.MAP_NULLABLE)
    email: string = '';
    @JsonProperty("contact", Contact, PropertyConvertingMode.PASS_NULLABLE)
    contact?: Contact = new Contact();
}
PropertyConvertingMode.MAP_NULLABLE:
This is the default conversion mode. An exception will be thrown if there is no JSON property corresponding to this property of the TypeScript class.
PropertyConvertingMode.IGNORE_NULLABLE:
Property of TypeScript object will get default value if there is no corresponding property in JSON.
PropertyConvertingMode.PASS_NULLABLE:
Property of TypeScript object will be null if there is no corresponding property in JSON.
model_file2.ts
import {
    JsonObject, JsonProperty, JsonConvert, OperationMode,
    ValueCheckingMode, PropertyConvertingMode
} from "json2typescript";

import { Contact } from './model_file1';

@JsonObject("Company")
class Company {
    @JsonProperty("companyName", String, PropertyConvertingMode.MAP_NULLABLE)
    name: string = '';
    @JsonProperty("contact", Contact, PropertyConvertingMode.PASS_NULLABLE)
    contact?: Contact = new Contact();
}
If you use Visual Studio Code to write code, you may get an error message like below. See how to fix the error shared on stackoverflow:
Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig' to remove this warning.ts(1219)
json2typescript_ex1.ts
import {
    JsonObject, JsonConvert, OperationMode, ValueCheckingMode
} from "json2typescript";

import { Employee, Contact } from './model_file1';

// @see Employee class in model_file1.ts
let jsonStr = `  {
    "employeeName": "John Smith",
    "email": "john@example.com",
    "contact": {
       "address": "Address 1",
       "phone": "12345"
    }
} `;
let jsonConvert: JsonConvert = new JsonConvert();

// ----------- JSON Text to TypeScript Object ------------------  
let jsonObj: any = JSON.parse(jsonStr);  
let emp: Employee = jsonConvert.deserializeObject(jsonObj, Employee);
console.log('JSON to TypeScript:');
console.log(emp);
console.log(' ------------- ');

// ----------- TypeScript Object to JSON Text ------------------
let jsonText = jsonConvert.serialize(emp);
console.log('TypeScript to JSON:');
console.log(jsonText);
Output:
JSON to TypeScript:
Employee {
  name: 'John Smith',
  email: 'john@example.com',
  contact: Contact { address: 'Address 1', phone: '12345' }
}
 -------------
TypeScript to JSON:
{
  employeeName: 'John Smith',
  email: 'john@example.com',
  contact: { address: 'Address 1', phone: '12345' }
}
json2typescript_ex2.ts
import {
    JsonObject, JsonConvert, OperationMode, ValueCheckingMode
} from "json2typescript";

import { Employee, Contact } from './model_file1';

// @see Employee class in model_file1.ts
let jsonStr = `  {
   "employeeName": "John Smith",
    "email": "john@example.com"
} `;
let jsonConvert: JsonConvert = new JsonConvert();

// ----------- JSON Text to TypeScript Object ------------------
let jsonObj: any = JSON.parse(jsonStr);  
let emp: Employee = jsonConvert.deserializeObject(jsonObj, Employee);
console.log('JSON to TypeScript:');
console.log(emp);
console.log(' ------------- ');

// ----------- TypeScript Object to JSON Text ------------------
let jsonText = jsonConvert.serialize(emp);
console.log('TypeScript to JSON:');
console.log(jsonText);
Output:
JSON to TypeScript:
Employee {
  name: 'John Smith',
  email: 'john@example.com',
  contact: undefined
}
-------------
TypeScript to JSON:
{
  employeeName: 'John Smith',
  email: 'john@example.com',
  contact: undefined
}

4. @JsonProperty

A property of a TypeScript object can be converted to a property of JSON if it is annotated by @JsonProperty. Otherwise, it will be ignored.
All properties of the TypeScript class annotated by @JsonProperty must be set to default values. Otherwise, the result may not be what you expect.
Example:
// Model class:
@JsonObject("User")
export class User {
    @JsonProperty("userName", String, PropertyConvertingMode.MAP_NULLABLE)
    userName: string = '';
    @JsonProperty("joinDate", DateConverter)
    joinDate: Date = new Date();
}
Syntax:
@JsonProperty("JSON_Property_Name", JSON_Type, Custom_Converter, PropertyConvertingMode)
JSON_Property_Name
Name of property in JSON.
JSON_Type (Optional)
A JSON data type.
  • String, [String]
  • Number, [Number]
  • Boolean, [Boolean]
  • Any, [Any]
Custom_Converter (Optional)
See examples at @JsonConverter section.
PropertyConvertingMode (Optional)
PropertyConvertingMode.MAP_NULLABLE:
  • This is the default conversion mode. An exception will be thrown if there is no JSON property corresponding to this property of the TypeScript class.
PropertyConvertingMode.IGNORE_NULLABLE:
  • Property of TypeScript object will get default value if there is no corresponding property in JSON.
PropertyConvertingMode.PASS_NULLABLE:
  • Property of TypeScript object will be null if there is no corresponding property in JSON.

5. @JsonConverter

In some cases, you may need to make custom conversion between JSON objects and TypeScript objects. You can define custom converters like this:
model_file3.ts
import {
    JsonObject, JsonProperty, JsonConvert, OperationMode,
    ValueCheckingMode, PropertyConvertingMode, JsonConverter, JsonCustomConvert
} from "json2typescript";
// Custom Converter:
@JsonConverter
class DateConverter implements JsonCustomConvert<Date> {
    serialize(date: Date): any {
        return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
    }
    deserialize(date: any): Date {
        return new Date(date);
    }
}
// Model class:
@JsonObject("User")
export class User {
    @JsonProperty("userName", String, PropertyConvertingMode.MAP_NULLABLE)
    userName: string = '';
    @JsonProperty("joinDate", DateConverter)
    joinDate: Date = new Date();
}
json2typescript_ex3.ts
import {
    JsonObject, JsonConvert, OperationMode, ValueCheckingMode
} from "json2typescript";

import { User  } from './model_file3';

// @see User class in model_file3.ts
let jsonStr = `  {
   "userName": "tom",
    "joinDate": "2021-12-15"
} `;
let jsonConvert: JsonConvert = new JsonConvert();

// ----------- JSON Text to TypeScript Object ------------------
let jsonObj: any = JSON.parse(jsonStr);  
let user: User = jsonConvert.deserializeObject(jsonObj, User);
console.log('JSON to TypeScript:');
console.log(user);
console.log(' ------------- ');

// ----------- TypeScript Object to JSON Text ------------------
let jsonText = jsonConvert.serialize(user);
console.log('TypeScript to JSON:');
console.log(jsonText);
Output:
JSON to TypeScript:
User { userName: 'tom', joinDate: 2021-12-15T00:00:00.000Z }
 -------------
TypeScript to JSON:
{ userName: 'tom', joinDate: '2021-12-15' }