How do I cast a JSON Object to a TypeScript class?

Solution 1:

You can't simple cast a plain-old-JavaScript result from an Ajax request into a prototypical JavaScript/TypeScript class instance. There are a number of techniques for doing it, and generally involve copying data. Unless you create an instance of the class, it won't have any methods or properties. It will remain a simple JavaScript object.

While if you only were dealing with data, you could just do a cast to an interface (as it's purely a compile time structure), this would require that you use a TypeScript class which uses the data instance and performs operations with that data.

Some examples of copying the data:

  1. Copying AJAX JSON object into existing Object
  2. Parse JSON String into a Particular Object Prototype in JavaScript

In essence, you'd just :

var d = new MyRichObject();
d.copyInto(jsonResult);

Solution 2:

I had the same issue and I have found a library that does the job : https://github.com/pleerock/class-transformer.

It works like this :

let jsonObject = response.json() as Object;
let fooInstance = plainToClass(Models.Foo, jsonObject);
return fooInstance;

It supports nested children but you have to decorate your class's member.

Solution 3:

In TypeScript you can do a type assertion using an interface and generics like so:

var json = Utilities.JSONLoader.loadFromFile("../docs/location_map.json");
var locations: Array<ILocationMap> = JSON.parse(json).location;

Where ILocationMap describes the shape of your data. The advantage of this method is that your JSON could contain more properties but the shape satisfies the conditions of the interface.

However, this does NOT add class instance methods.

Solution 4:

If you are using ES6, try this:

class Client{
  name: string

  displayName(){
    console.log(this.name)
  }
}

service.getClientFromAPI().then(clientData => {
  
  // Here the client data from API only have the "name" field
  // If we want to use the Client class methods on this data object we need to:
  let clientWithType = Object.assign(new Client(), clientData)

  clientWithType.displayName()
})

But this method will not work on nested objects, sadly.

Solution 5:

I found a very interesting article on generic casting of JSON to a Typescript Class:

http://cloudmark.github.io/Json-Mapping/

You end up with following code:

let example = {
                "name": "Mark", 
                "surname": "Galea", 
                "age": 30, 
                "address": {
                  "first-line": "Some where", 
                  "second-line": "Over Here",
                  "city": "In This City"
                }
              };

MapUtils.deserialize(Person, example);  // custom class