8/10/19

TypeScript Interface JSON Type Inference

The JavaScript Object Notation (JSON) is used to build complex data structures or documents which make the data model easy to manage with JavaScript. The biggest benefit of JSON is that it uses schemaless and dynamic data types which provide the flexibility to support changes in the data model. This flexibility however also provides a drawback in the fact that by not using strongly typed models, we can run into runtime errors because of the lack of static verification (compile) of some of the types. 



TypeScript is a JavaScript framework that encourages the used of strongly typed data models. By enabling us to create classes and interfaces with well-defined types, we can have type inference from JSON and static verification of the code. Even though this is ideal to have, it deviates from the principals of dynamic datatypes which JavaScript so well used. This poses a new challenge to developers as we now have to understand how to map a JSON document into a TypeScript interface. To help us understand this better, let’s take a look at a JSON document and define the interface that can enable our code with type inference and static type verification.

JSON Document 

We start the process by looking at a vehicle inventory JSON document.  The document is a list of vehicles that have these properties (year, make, model, sold and new).  By inspecting the document visually, we can infer the data types like string, number, date, and boolean, but in the code, we need to provide annotations to be able to support type inference.


var list = [{
  'year': 2018,
  'make': 'nissan',
  'model': 'xterra',
  'sold': '2018-07-01'
}, {
  'year': 2018,
  'make': 'nissan',
  'model': 'altima',
  'new': true
}, {
  'year': 2018,
  'make': 'nissan',
  'model': 'maxima',
  'new': true
}]

Building the Vehicle Interface

In order to build our interface,  let’s start by looking at all the possible properties that are available on the document.  By looking carefully, we can notice that there are three main properties available on all the records (year, make, model). There are other optional properties that may be present (sold, new). The optional properties are nullable types as they may exist for a record or not. With that information we can create this interface:


interface Vehicle {
  year: number;
  make: string;
  model: string;
  sold ? : Date;
  new ? : boolean;
}

We should notice that we define strongly typed properties with string, number, date, and boolean types.  We should also notice that the sold and new properties have a question mark (?) notation which is used to denote the nullable types.

Using the Interface 

Now that we have the interface for each object in the list, we need to define a variable that we can use to assign the JSON document. If we recall, our JSON is an array of vehicles. Each vehicle can be accessed via a numeric index. We can use our interface to map our JSON document with the following code snippet:


const inventory: Vehicle[] = list as Vehicle[];

inventory.forEach((item: Vehicle) => {
  console.log(typeof(item.year), typeof(item.make), typeof(item.sold));
})

In our snippet, we assign the JSON document as an array of Vehicles. We then iterate the list and print the type for some of the properties.

Conclusion

By adding the interface, we can now support type inference and statically validate the code. If for some reason the JSON model changes one of its properties to a different type, the mapping will not take place and during the compilation of the code, an error would be raised.

With this article, we want to be able to describe the process of creating interface annotations when it comes to mapping JSON documents. We also want to be able to describe the benefits of JavaScript type inference and static code validation, so we can avoid runtime errors on the code. 


I hope this was helpful and provides some insights on how to map JSON documents to a TypeScript interface.  

Originally published by ozkary.com