TypeScript: Working with JSON
At some point you’re going to want to encode this as JSON. This works as you’d expect.
The problem is that the created field is no longer a Date when you parse it back.
The way I went about fixing this is by introducing a UserJSON interface.
Since it only contains primitives, it can be converter to and from JSON without altering it.
interface UserJSON name: string; age: number; created: string; >
Then I convert from User -> UserJSON before ‘stringifying’ to JSON and convert from UserJSON -> User after parsing from JSON. Here’s an example of some client code doing this.
function getUsers(): PromiseUser[]> return ajax.getUserJSON[]>('/users').then(data => return data.data.map(decodeUser); >); > function updateUser(id: number|string, user: User): Promise<>> return ajax.put<>>(`/users/$id>`, encodeUser(user)); >
Here are the conversion functions.
function encodeUser(user: User): UserJSON return name: user.name, age: user.age, created: user.created.toString() >; > function decodeUser(json: UserJSON): User return name: json.name, age: json.age, created: new Date(json.created) >; >
This works, but it’s a contrived example. In real cases, there will be a lot more properties and this quickly turns into a huge pain in the ass. Let’s use Object.assign to clean it up a bit.
function encodeUser(user: User): UserJSON return Object.assign(<>, user, created: user.created.toString() >); > function decodeUser(json: UserJSON): User return Object.assign(<>, json, created: new Date(json.created) >); >
So far so good, but what happens when User is a class?
class User private created: Date; constructor( private name: string, private age: string ) this.created = new Date(); > getName(): string return this.name; > >
For this to work, I use Object.create to make a new instance of User without using the constructor. Then assign the properties to that. The encoding function doesn’t change.
function decodeUser(json: UserJSON): User let user = Object.create(User.prototype); return Object.assign(user, json, created: new Date(json.created) >); >
Finally, the encode and decode functions can just be methods on the User class.
class User private created: Date; constructor( private name: string, private age: string ) this.created = new Date(); > getName(): string return this.name; > encode(): UserJSON return Object.assign(<>, this, created: this.created.toString() >); > static decode(json: UserJSON): User let user = Object.create(User.prototype); return Object.assign(user, json, created: new Date(json.created) >); > >
When JSON.stringify is invoked on an object, it checks for a method called toJSON to convert the data before ‘stringifying’ it. In light of this, let’s rename encode and decode to toJSON and fromJSON .
class User /* . */ toJSON(): UserJSON return Object.assign(<>, this, created: this.created.toString() >); > static fromJSON(json: UserJSON): User let user = Object.create(User.prototype); return Object.assign(user, json, created: new Date(json.created) >); > >
We don’t need to call user.encode() explicitly anymore!
let data = JSON.stringify(new User("Steve", 39)); let user = User.fromJSON(JSON.parse(data));
This is good, but we can do better. JSON.parse accepts a second parameter called reviver which is a function that gets called with every key/value pair in the object as it’s being parsed. The root object is passed to reviver with an empty string as the key. Let’s add a reviver function to our User class.
class User /* . */ static reviver(key: string, value: any): any return key === "" ? User.fromJSON(value) : value; > >
let user = JSON.parse(data, User.reviver);
The nice thing about using this pattern is that it composes very well.
Say the user had an account property which contained an instance of Account .
class User private account: Account; /* . */ static fromJSON(json: UserJSON): User let user = Object.create(User.prototype); return Object.assign(user, json, created: new Date(json.created), account: Account.fromJSON(json.account) >); > >
And here’s the full commented User class.
class User private created: Date; constructor( private name: string, private age: string ) this.created = new Date(); > getName(): string return this.name; > // toJSON is automatically used by JSON.stringify toJSON(): UserJSON // copy all fields from `this` to an empty object and return in return Object.assign(<>, this, // convert fields that need converting created: this.created.toString() >); > // fromJSON is used to convert an serialized version // of the User to an instance of the class static fromJSON(json: UserJSON|string): User if (typeof json === 'string') // if it's a string, parse it first return JSON.parse(json, User.reviver); > else // create an instance of the User class let user = Object.create(User.prototype); // copy all the fields from the json object return Object.assign(user, json, // convert fields that need converting created: new Date(json.created), >); > > // reviver can be passed as the second parameter to JSON.parse // to automatically call User.fromJSON on the resulting value. static reviver(key: string, value: any): any return key === "" ? User.fromJSON(value) : value; > > // A representation of User's data that can be converted to // and from JSON without being altered. interface UserJSON name: string; age: number; created: string; >
Parsing JSON in TypeScript
Follow us on our fanpages to receive notifications every time there are new articles.
Facebook
Twitter
1- TypeScript JSON
As you know, TypeScript can be considered as an enhanced version of JavaScript. Finally, TypeScript is also converted to JavaScript code that can be executed in the browser or other JavaScript environments such as NodeJS. TypeScript supports all JavaScript libraries and API documentation.
The simplest way to parse JSON data is to use JSON.parse(..) and JSON.stringify(..) methods. There is no difference in how to use them in JavaScript and TypeScript.
// Static methods: parse(text: string, reviver?: (this: any, key: string, value: any) => any): any; stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string; stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
Consider using one of the JSON libraries below if you are developing a large TypeScript project.
2- JSON.parse(..)
parse(text: string, reviver?: (this: any, key: string, value: any) => any): any;
- text: A JSON text.
- reviver: An optional function called for each property of this JSON. The Typescript convert json to object parameter corresponds to the global JSON object. Leaf-level properties will be executed first, root-level properties will be executed last.
Example: Use the JSON.parse(..) method to convert a JSON text into an object.
function json_parse_ex1_test() < let jsonString = ` < "name": "John Smith", "email": "[email protected]", "contact": < "address": "Address 1", "phone": "12345" >> `; // Return an object. let empObj = JSON.parse(jsonString); console.log(empObj); console.log(`Address: $`); > json_parse_ex1_test(); // Call the function.
< name: 'John Smith', email: '[email protected]', contact: < address: 'Address 1', phone: '12345' >> Address: Address 1
Example: Use the JSON.parse(..) method with the participation of the reviver function, to convert a JSON text into an object of a class.
class Employee < employeeName: string; employeeEmail: string; contact: Contact; constructor(employeeName: string, employeeEmail: string, contact: Contact) < this.employeeName = employeeName; this.employeeEmail = employeeEmail; this.contact = contact; >> class Contact < address: string; phone: string; constructor(address: string, phone: string) < this.address = address; this.phone = phone; >> function json_parse_ex2_test() < let jsonString = ` < "name": "John Smith", "email": "[email protected]", "contact": < "address": "Address 1", "phone": "12345" >> `; // Return an object. let empObj = JSON.parse(jsonString, function (key: string, value: any) < if(key == 'name') < return (value as string).toUpperCase(); // String. >else if (key == 'contact') < return new Contact(value.address, value.phone); >else if (key == '') < // Entire JSON return new Employee(value.name, value.email, value.contact); >return value; >); console.log(empObj); console.log(`Employee Name: $`); console.log(`Employee Email: $`); console.log(`Phone: $`); > json_parse_ex2_test(); // Call the function.
Employee < employeeName: 'JOHN SMITH', employeeEmail: '[email protected]', contact: Contact < address: 'Address 1', phone: '12345' >> Employee Name: JOHN SMITH Employee Email: [email protected] Phone: 12345
3- JSON.stringify(..) *
stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
- value: A value, usually an object or an array, to convert to JSON text.
- replacer: An optional function, used to customize the results.
- space: Add indents, spaces, or line break characters to JSON text to make it easier to read.
console.dir(JSON.stringify(1)); console.dir(JSON.stringify(5.9)); console.dir(JSON.stringify(true)); console.dir(JSON.stringify(false)); console.dir(JSON.stringify('falcon')); console.dir(JSON.stringify("sky")); console.dir(JSON.stringify(null));
'1' '5.9' 'true' 'false' '"falcon"' '"sky"' 'null'
function json_stringify_ex1b_test() < // An Object: let emp = < name: 'John Smith', email: '[email protected]', contact: < address: 'Address 1', phone: '12345' >>; let jsonString = JSON.stringify(emp); console.log(jsonString); > json_stringify_ex1b_test(); // Call the function.
function json_stringify_replacer_ex1a_test() < // An Object: let emp = < name: 'John Smith', email: '[email protected]', contact: < address: 'Address 1', phone: '12345' >>; let jsonString = JSON.stringify(emp, function (key: string, value: any) < if (key == 'contact') < return undefined; >else if (key == 'name') < return (value as string).toUpperCase(); >return value; >); console.log(jsonString); > json_stringify_replacer_ex1a_test(); // Call the function.
4- JSON.stringify(..) **
stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
- value: A value, usually an object or an array, to convert to JSON text.
- replacer: An optional array of strings or numbers. As a list of approved properties, they will appear in the returned JSON text.
- space: Add indents, spaces, or line break characters to JSON text to make it easier to read.
function json_stringify_replacer_ex2a_test() < // An Object: let emp = < name: 'John Smith', email: '[email protected]', contact: < address: 'Address 1', phone: '12345' >>; let replacer = ['email', 'contact', 'address']; let jsonString = JSON.stringify(emp, replacer, ' '); console.log(jsonString); > json_stringify_replacer_ex2a_test(); // Call the function.
View more Tutorials:
These are online courses outside the o7planning website that we introduced, which may include free or discounted courses.
Basics of GraphQL with Ruby on Rails
Learn Ruby on Rails for Absolute Beginners
Learn NodeJS in Hours
Mastering Thymeleaf with Spring Boot
Learning Oracle Application Express ( Oracle Apex ) Training
* * Cloning Amazon, Netflix & Spotify
AWS CloudFormation Master Class
iPhone Programming from Zero to App Store, Swift 4 + iOS11
Create an Android Game from Scratch using AndEngine
Create Complete Web Applications easily with APEX 5
CSS3 Master Series: CSS Animations, Transforms & Transitions
C#: The Complete Foundation!
LEARNING PATH: SQL: Securing Data with SQL Server on Linux
Learning MongoDB-Volume 3
Java Fx Concepts With Practical Examples
What’s New in C#7 and C# 8
Mastering SQL Server 2016 Integration Services (SSIS)-Part 1
Learn Spring Boot — Rapid Spring Application Development
Java, JSP and JDBC programming guides for complete BEGINNER
Building A Scalable Serverless Application on AWS
AngularJs Practical Session to be an Angular Jedi
Learn Database Design using PostgreSQL
PHP Tutorial: PHP/MySQL for Beginners
C# Unity® and Swift 4 Masterclass: Make Games and Apps
Master Microservices with Spring Boot and Spring Cloud