Modelling Cloudant data in TypeScript

Using TypeScript classes in your code and saving their JSON representation in a Cloudant database.

TypeScript is programming language that is a super-set of JavaScript written by Microsoft. TypeScript code compiles to various flavours of JavaScript to run in the browser, in Node.js or in concert with frameworks such as React, Angular, Vue.js etc. Programming in TypeScript brings you the luxury of:

  • type checking for function parameters, return values etc
  • default and optional values for function parameters
  • interfaces, for defining the shape of objects being passed in and out of functions
  • classes with constructors, inheritance & access modifiers
  • enumerations
  • iterators
  • module import/export
  • and lots more

Ultimately your TypeScript code is transpiled into JavaScript, targetted for your destination platform, so it can’t do any more than JavaScript. The advantage of TypeScript code is that you get to apply greater rigour in your code, have access to lots of “grown up” programming features and a receive lots of help in the code editor.

in-editor warnings help catch bugs early

In the above example, the red line indicates that there is no ‘postcode’ property of the Address class. Catching mistakes like this in the editor saves lots of time later, chasing down errors and figuring out why the code isn't doing what is expected.

Typescript is open-sourced and Microsoft’s popular VS Code editor is itself written in TypeScript!

Data modelling with Cloudant

Let’s say we want to store employee records in Cloudant. As Cloudant stores JSON objects, we can use plain JavaScript objects in our code that are transformed to JSON with JSON.stringify:

Modelling data using plain JavaScript objects and only core data types.

To take advantage of the features of TypeScript, it would be better if we could use classes instead of generic objects. We could build:

  • a Date object to represent the time the employee joined.
  • an Address object with custom methods that formats address lavels.
  • a TagsCollection object with methods that allow new tags to be added and prevents duplicates.
Modelling, you see. Photo by SwapnIl Dwivedi on Unsplash

Ideally, an Employee class containing these building-block classes would have a usuable JSON representation that could be stored in Cloudant. In addtion, the JSON string could be returned to a concrete class after retrieving data from the database.

There is a solution to this, so let’s start with a custom Address class.

Address class

We can create a custom TypeScript class that embodies a postal address and geo-location:

An class to model a postal address

It’s worth explaining that a TypeScript Interfaces define the forms of objects — the attributes and types that make up an object. They are useful when defining functions that take objects as parameters — this allows the TypeScript compiler to check the form of the object at compile-time and allows your editor to check your code as you type.

This Address object is pretty simple. It has a number of public attributes that define the address, a getLabel function that returns a postage label and a static fromObject function that can resurrect an Address object from a generic object that conforms to the iAddress interface.

A simple class like Address that only uses JavaScript primitive types turns into a sensible form of JSON — an object which looks like the iCloudantDate interface:

This simple object turns into the equivalent JSON without any help.

We’ll see how to incorporate this into our Employee class later, but first let’s look at how we can use a similar technique to model a date.

The CloudantDate class

In this blog post, I discussed various ways of representing a date/time in Cloudant JSON. I concluded that it’s good to have the constituent date/time parts (day, month, year) present in the object to allow Cloudant Query to access them and a “seconds since 1970” integer or an ISO-8601 string for sorting purposes.

To represent a JavaScript Date object in our Employee class, we’re going to create a wrapper class called CloudantDate which has a trick up its sleeve:

Modelling a Date object, but ensuring that its JSON form is more detailed.

The CloudantDate class stores its value in a standard JavaScript Date class and like Address, implements a static fromObject function to allow a class to be reconstituted from an plain object. CloudantDate's real party piece is overridng the toJSON function, which is used by JSON.stringify to turn an instance of the class into JSON.

If we create a CloudantDate object and JSON.stringify it, the resultant string contains all the date and time pieces broken out:

This time the JSON contains all the date/time pieces

This allows us to have dates that are useable Date classes in our code and have the constituent parts broken down in the Cloudant database, where they are accessible to the Cloudant indexing engine.

TagCollection class

Our final storage class is TagCollection which stores an array of strings. It has a couple of helper functions (add and remove) and also overrides the toJSON function to ensure that only an array of strings appears in the JSON:

Simple TagCollection object with add/remove helpers
The JSON representation is just the array of tags

Assembling the Employee class

Now we have all the pieces in place, we can create a top level “Employee” class that uses our custom classes:

The Employee class uses the other classes and extends CloudantDocument

We have a base class that handles the Cloudant-specific fields (_id, _rev etc) which we can reuse across all of our Cloudant storage classes:

CloudantDocment models the Cloudant specific fields (ones beginning with _ )

We can then use the Employee class in our own code and pass instances of Employee to the official Node.js Cloudant library to be stored in the database:

Using the Employee class

The Cloudant library converts the our custom object to JSON, which invokes our custom toJSON overrides:

When turned into JSON, it uses all the helper class’s toJSON overrides

The Cloudant document can be restored into an Employee class later, if we use our static Employee.fromObject method to reconstitute the class from its JSON form:

and the fromObject can turn the JSON form back into an instance of the class again

Typescript conclusions

Writing in TypeScript adds some of the rigour of writing Java code to JavaScript, including strong typing and classes with inheritance & access control. This allows the developer to build neat, consistent code with the code editor advising at every turn. TypeScript is transpiled, whether your target is a minified package for a web app, a server-side Node.js module or a native Electron app.

Overriding the toJSON function in your custom TypeScript classes allows you to use classes in your code and pass them to the Cloudant Node.js library to be saved in a form of JSON of your choice.