Javier Enríquez
Javier Enríquez

Reputation: 630

Typescript object from JSON

I'm using TypeScript to build an app and I'm making API calls to retrieve objects. For instance, I have a TypeScript User Object like this:

export class User {
    id : number;
    name : string;
    email : string;
}

And my API returns

{
    "id" : 3,
    "name" : "Jonn",
    "email" : "[email protected]"
}

I want to convert that JSON to a User. I've read in another posts I can do this:

let user : User = <User> myJson;

This seemly works. I can access properties of the user like user.namebut my problem is that, if the User class implements some method, the properties are not available. For example, if inside the User class I have this:

getUppercaseName() : string {
    return this.name.toUppercase();
}

This happens: user.name returns John but user.getUppercaseName() returns undefined

What's going on? How to solve this

Upvotes: 1

Views: 797

Answers (3)

Anthony Breneli&#232;re
Anthony Breneli&#232;re

Reputation: 63450

There is a problem when your User has 50 or more properties...

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

export class User {
    constructor( jsonUser: any )
    {
      $.extend(this, jsonUser);
    }
    id : number;
    name : string;
    email : string;
    getUpperCaseName() {...}
}

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

let receivedUser = new User( jsonUser );
let userName = receivedUser.getUpperCaseName();

I detailed the solution in that post.

Upvotes: 0

tedcurrent
tedcurrent

Reputation: 431

Nitzan pretty much explained the theory behind this, so I'll just provide an alternative approach:

interface UserInfo {
   id: number;
   name: string;
   email: string;
}

class User {
   userInfo: UserInfo;
   constructor(userInfo: UserInfo) {
       this.userInfo = userInfo;
   }
   getUpperCaseName(): string {
       return this.userInfo.name.toLocaleUpperCase();
   }
}

const json = {
   id: 3,
   name: "Jonn",
   email: "[email protected]"
}

let user: User = new User(json);

Upvotes: 2

Nitzan Tomer
Nitzan Tomer

Reputation: 164129

What you are doing it treating classes as interfaces, as this will work exactly the same:

export interface User {
    id : number;
    name : string;
    email : string;
}

The reason that the compiler doesn't complain about you using classes this way is because:

One of TypeScript’s core principles is that type-checking focuses on the shape that values have. This is sometimes called “duck typing” or “structural subtyping”

(read more about duck typing)

Or with an example:

class User {
    id: number;
    name: string;
    email: string;

    constructor(id: number, name: string, email: string) {
        this.id = id;
        this.name = name;
        this.email = email;
    }
}

function logUser(user: User) {
    console.log(`user id: ${ user.id }, name: ${ user.name }, email: ${ user.email }`);
}

logUser({
    id: 1,
    name: "user 1",
    email: "mailaddress"
});

logUser(new User(2, "user 2", "anotheraddress"));

In the two calls to logUser I pass objects that satisfy the interface of the User class.

If you want to have an instance of that class instead of an object that satisfies it then you should do something like:

new User(myJson.id, myJson.name, myJson.email);

And have a constructor like in my example, or:

interface IUser {
    id: number;
    name: string;
    email: string;
}

class User implements IUser {
    id: number;
    name: string;
    email: string;

    constructor(data: IUser) {
        this.id = data.id;
        this.name = data.name;
        this.email = data.email;
    }
}

...
new User(myJson);

Upvotes: 2

Related Questions