2

Let be this JSON string:

[
    {
        "id": 1,
        "text": "Jon Doe"
    },
    {
        "id": 1,
        "text": "Pablo Escobar"
    }
]

Let be this class:

export class MyObject{
    id: number;
    text: string;
}

How can I cast this JSON string to list of MyObject?

If I do:

console.log(<MyObject[]>JSON.parse(json_string));

It returns a list of Object instead of a list of MyObject

Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
Ben
  • 3,972
  • 8
  • 43
  • 82
  • 3
    Possible duplicate of [How do I cast a JSON object to a typescript class](http://stackoverflow.com/questions/22875636/how-do-i-cast-a-json-object-to-a-typescript-class) – xmojmr Oct 21 '16 at 10:15

4 Answers4

8

You don't necessarily need a class here. You can just use an interface

export interface MyObject{
  id: number;
  text: string;
}

Then you can just write:

var myObjArray : MyObject[] =  [
  {
    "id": 1,
    "text": "Jon Doe"
  },
  {
    "id": 1,
    "text": "Pablo Escobar"
  }
];

If you data comes from the server, you will probably have it in a variable of type any, and you can just assign it to an array of that type and it will work as expected.

var data: any = getFromServer();
var myObjectArray:MyObject[] = data;

In typescript you don't need a class implementing an interface. Any object literal that satisfies the interface contract will do.

If your data is still in string for you can just use JSON.parse(jsonString) to parse the string to JavaScript objects.

See playground here

Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
  • Thanl you for your reply. But the returned object is still not an `MyObject` type. When I log it in the console it says that it's an `Object`. What am I doing wrong? – Ben Oct 21 '16 at 09:02
  • It doesn't need to say MyObject, it will work. Typescript types are more about describing the shape of a Javascript Object. If the object satisfies the contract it should be fine. Is there a specific error you are getting? Does the Object you see in the console have the id and text properties ? If so it should work. – Titian Cernicova-Dragomir Oct 21 '16 at 09:17
  • And since MyObject is now an interface, it will not have any actual presence in JS output, interfaces are wiped away by TS compilation, they are just there to allow you to describe the shape of JS objects – Titian Cernicova-Dragomir Oct 21 '16 at 09:18
  • Yes, the object has the properties. But what I don't understand is that if I instantiate a new `MyObject` and map the properties, the console show the `MyObject` type. – Ben Oct 21 '16 at 09:20
  • And if the given JSON doesn't fit the class description (for exemple if the JSON has a property which doesn't exists in the class), the generated object still have this property. Should he not throw an error? – Ben Oct 21 '16 at 09:26
  • 2
    If the JSON does not fit the description there will be no error you just can't access any extra properties from typescript (unless you add them to the interface as well) – Titian Cernicova-Dragomir Oct 21 '16 at 13:53
  • 2
    @Ben Nitzan Tomer is right about using classes if you plan to also have methods, but if your looking for just simple object to hold data there is no need to create an extra clss – Titian Cernicova-Dragomir Oct 21 '16 at 13:54
6

You will need to create a constructor for your class, and call it for each item in the list you receive.

export class MyObject{
    constructor(public id: number, public text: string) { }
}

let data = [
  {
    "id": 1,
    "text": "Jon Doe"
  },
  {
    "id": 1,
    "text": "Pablo Escobar"
  }
];

let objects = data.map(o => new MyObject(o.id, o.text));

You can check it out in the playground here.

toskv
  • 30,680
  • 7
  • 72
  • 74
  • I have seen in many posts that it's possible to do it without to map each property, as suggested by @Titian Cernicova-Dragomir. What is the truth? Is there really a way to do it without mapping? – Ben Oct 21 '16 at 09:12
  • 3
    @Ben It depends what you're looking for. If you want a data object only then you can go with interfaces as TitianCernicovaDragomir answered. However, if you want to also have methods on the objects then you need to instantiate class instances, and toskv solution is the one you're looking for. – Nitzan Tomer Oct 21 '16 at 10:19
  • 1
    @Ben if you need to add some more methods you need my solution, if you just need to use the objects as they come from the server the interface solution is more appropiate. :) – toskv Oct 21 '16 at 10:30
  • @toskv .map() function looks good on const JSON data but it's not applicable on type HTTPResponse. Thanks anyway. – Sudeep Rane Feb 06 '18 at 12:23
  • you didn't specify how you come to get the array. I just started from the array onwards. :) – toskv Feb 06 '18 at 15:33
1

There is a problem when MyObject has 50 or more properties...

Add a constructor in your MyObject class so that it extends your json object.

export class MyObject {
    constructor( json: any )
    {
      $.extend(this, json);
    }
    id : number;
    text : string;

    methodOnMyObject() {...}
}

In your ajax callback, create the MyObject object from your json Object:

let newObject = new MyObject( json );
newObject.methodOnMyObject();

I detailed the solution in that post.

Community
  • 1
  • 1
Anthony Brenelière
  • 60,646
  • 14
  • 46
  • 58
  • If you want to use jquery $.extend method in your typescript file you need to enable jquery in your typescript files first by running `npm install --save @types/jquery` [see this answer](https://stackoverflow.com/a/43914578/7794769). – stomy Dec 07 '17 at 02:29
  • Should it not be `let newObject = new MyObject( JSON.parse(json) );` instead? – stomy Dec 07 '17 at 02:34
0

One more way to achieve this:

var data: any = getFromServer();
var myObjectArray = data as MyObject;

Or:

var data: any = getFromServer();
var myObjectArray = <MyObject>dataMyObject;
OlegI
  • 5,472
  • 4
  • 23
  • 31