Reputation: 630
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.name
but 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
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
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
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”
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