0

I'm trying to cast a complex (multiple type classes) json response object ( which i receive from my nodejs/mongoose backend) to a typescript class.

A moment class contains an author of type user and a comments array of type comment.

moment.model.ts

    import { Comment } from './comment.model';
import { User } from './user.model';

export class Moment {

    _id?: string = null;
    body?: string = null;
    _author?: User = null;
    likes?: any[] = [];
    dislikes?: any[] = [];
    _comments?: Comment[] = [];
    created_at?: string = null;
    updated_at?: string = null;


    constructor(data?: Moment) {
        console.log(data);
        if (data) {
            this.deserialize(data);
        }
    }

    private deserialize(data: Moment) {
        const keys = Object.keys(this);

        for (const key of keys) {
            if (data.hasOwnProperty(key)) {
                this[key] = data[key];
            }
        }
    }

    public get author(): User {
        return this._author;
    }
    public set author(data: User) {
        this._author = new User(data);
    }

    public get comments(): Comment[] {
        return this._comments;
    }
    public set comments(data: Comment[]) {
        this._comments = data.map(c => new Comment(c));
    }
}

comment.model.ts

    export class Comment {

    _id?: string = null;
    body?: string = null;
    moment?: any = null;
    author?: any = null;
    likes?: any[] = [];
    dislikes?: any[] = [];
    parent?: any = null;
    replies?: any = null;
    updated_at?: string = null;
    created_at?: string = null;

    constructor(data?: Comment) {
        console.log(data);
        if (data) {
            this.deserialize(data);
        }
    }

    private deserialize(data: Comment) {
        const keys = Object.keys(this);

        for (const key of keys) {
            if (data.hasOwnProperty(key)) {
                this[key] = data[key];
            }
        }
    }

}

user.model.ts

 export class User {

    _id?: string = null
    updated_at?: string = null;
    created_at?: string = null;
    profile?: any = null;
    phone?: any = null;
    email?: any = null;
    followers: any[] = [];
    following: any[] = [];
    isOnline: any = null;
    socketId: any = null;


    constructor(data?: User) {
        console.log(data);
        if (data) {
            this.deserialize(data);
        }
    }

    private deserialize(data: User) {
        const keys = Object.keys(this);

        for (const key of keys) {
            if (data.hasOwnProperty(key)) {
                this[key] = data[key];
            }
        }
    }

moment.service.ts

    get(moment_id) {

    let endpoint = this.path + moment_id;

    return this.apiService.get(endpoint)
        .map((res) => new Moment(res.data));

}

moment-detail.component.ts

this.route.params.switchMap((params) => {
    let moment_id = params['id'];
    return this.momentService.get(moment_id);
}).subscribe((res) => {

    this.moment = res;
    console.log(this.moment);
});

When i call my service i assign the json to a new class of Moment. In the component i then try to print this.moment. Everything is fine except for the author and a comments which are null/empty.

7
  • _author is of type User and values will get assigned to members of _author only if you call like new User( data[key]). Otherwise, because of type compatibility, you will get the error and it gives null which is expected. Commented Dec 4, 2017 at 12:27
  • If you bring a Moment example, we can test it more easily. Don't you think? Also I think you should erase javascript label, because in this code there is not any javascript code (even when you are using node.js as backend). And just as curiosity, why you use a copy constructor (deserialize inside constructor)? Do you need it actually? Commented Dec 4, 2017 at 12:27
  • @SantoshHegde ye i think i understand that issue, is there a solution to it? Commented Dec 4, 2017 at 12:30
  • @JTejedor yes i need it, thats the whole point, im trying to cast json data to a typescript class. Commented Dec 4, 2017 at 12:33
  • This is not really casting. You're constructing a Moment (with new Moment) but I don't see the other classes being called anywhere? Commented Dec 4, 2017 at 12:44

2 Answers 2

1

Your deserialize method in Moment is treating every field the same way and just copying the value from the JSON. This means it never constructs User or Comment objects. You should probably write it "by hand" to deal with each property correct, instead of using a loop.

Sign up to request clarification or add additional context in comments.

3 Comments

Yes i dont need getters and setters, just have to rebuild my class. Im just wondering how efficient this is.
Efficient in what sense? Rarely worth worrying about runtime efficiency for something like this. More important to consider maintainability.
sorry, thats what i meant, im trying to refactor some functions i have related to moments into the model instead of them being scattered in components.
1

You can try something like

this[key]=( key=='_author' ? new User(data[key]):(key=='_comments'?new Comment(data[key]): data[key]))

Or

if(key=='_author')
    this[key]=new User(data[key]);
else if(key=='_comments')
    this[key]=new Comment(data[key]);
else
    this[key]=data[key]

2 Comments

thank you, although this isent the correct solution it helped me
Its better to re-write your code. Its not written well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.