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.