angular2 map data as specific object type

2020-03-01 15:32发布

问题:

I created a very simple app based on the Angular2 tutorial.

To start, I have a very simple "Book" model:

 /**
 * book model
 */
export class Book {
    public data;

    /**
     * constructor
     * @param id
     * @param title
     * @param pages
     */
    constructor(
        public id,
        public title:string,
        public pages:Array
    ){
        alert('it works'); // just a check
    }
}

In my service, I get a book like this:

return this._http.get('getBook/1')
        .map(function(res){
            return <Book> res.json();
        })

My expectation was that this would get the resulting JSON data and "map" it to a Book object.

However, it just returns an object with type "Object".

I could create a new Book object myself and pass the parameters in the constructor, like this:

return new Book(res.id, res.title, res.pages);

Is this the best way to do this? Did I miss something?

回答1:

Yes, casting an object to a type in TypeScript doesn't create an instance of this type. It's just a facility of TypeScript for type checking.

If you want actually an instance of Book you need to use something like that:

return this._http.get('getBook/1')
    .map(function(res){
        var data = res.json();
        return new Book(data.id, data.title, data.pages);
    })

To answer your question. In fact if you only have fields into your type (with an interface for example), casting is enough. Moreover if you have methods you want to use later, it's necessary to implicitly create an instance of the Book type (see above) instead of casting. Otherwise you won't be able to use them (they will be undefined on your object)...

See this question for more details:

  • How do I cast a JSON object to a typescript class


回答2:

Good practice is to consume data from GET response using

Observable<Model>

(regarding to Angular documentation https://angular.io/guide/http) And then:

// imports

import {HttpClient} from "@angular/common/http";

// in constructor parameter list

private http: HttpClient

// service method

getBook(): Observable<Book> {return this.http.get<Book>({url}, {options});}


回答3:

I think you should declare an interface Book instead of class book:

export interface Book {
    public id;
    public title:string;
    public pages:Array;
}

In your service:

//get one record
return this._http.get('getBook/1')
        .map(function(res){
            return <Book> res.json();
        });

//get multi record
return this._http.get('getBooks')
        .map(function(res){
            return <Book> res.json();
        });