Я создал очень простое приложение на основе учебника Angular2.

Для начала у меня есть очень простая модель "Книга":

 /**
 * 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
    }
}

К себе на службу попала такая книга:

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

Я ожидал, что это приведет к получению результирующих данных JSON и «сопоставит» их с объектом Book.

Однако он просто возвращает объект с типом «Object».

Я мог бы сам создать новый объект Book и передать параметры в конструктор, например:

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

Это лучший способ сделать это? Я что-то пропустил?

11
Kris 28 Апр 2016 в 13:03

4 ответа

Лучший ответ

Да, приведение объекта к типу в TypeScript не создает экземпляр этого типа. Это просто средство TypeScript для проверки типов.

Если вам действительно нужен экземпляр Book, вам нужно использовать что-то вроде этого:

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

Чтобы ответить на ваш вопрос . Фактически, если у вас есть только поля в вашем типе (например, с интерфейсом), достаточно литья. Более того, если у вас есть методы, которые вы хотите использовать позже, необходимо неявно создать экземпляр типа Book (см. Выше) вместо приведения. В противном случае вы не сможете их использовать (они не будут определены на вашем объекте) ...

См. Этот вопрос для получения более подробной информации:

15
Community 23 Май 2017 в 12:17

Из https://angular.io/guide/http#requesting-a-typed -ответ

Чтобы указать тип объекта ответа, сначала определите интерфейс с необходимыми свойствами. Используйте интерфейс, а не класс, потому что ответ представляет собой простой объект, который не может быть автоматически преобразован в экземпляр класса.

Всегда получайте ответ через интерфейс, потому что происходит только отображение полей, и вы не можете использовать класс, если у вас есть функция экземпляра, которая выдает ошибку при использовании этого объекта.

product.getPrice is not a function

Пример

interface ProductInterface {
  id: number;
  name: string;
  price: number;
}

class Product implements ProductInterface {
  id: number;
  name: string;
  price: number;
  
  constructor(productData: ProductInterface) {
    this.id = product.id;
    this.name = product.name;
    this.price = product.price;
  }
  
  public getPrice(): string {
    return this.price + " INR";
  }
}
class ProducService {
  ...
  ...


  getProduct(): Observable<Product> {
    return this.http.get<Product>('assets/product.json').pipe(map(data => new Product(data))); 
  }

  getProductWithoutMappingToClass(): Observable<Product> {
    return this.http.get<Product>('assets/product.json');
  } // Throw runtimerror ctx_r1.product.getPrice is not a function
}

0
imechemi 27 Июл 2020 в 06:18

Хорошая практика - использовать данные из ответа GET, используя

Observable<Model>

(относительно документации Angular https://angular.io/guide/http) А потом:

// импорт

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

// в списке параметров конструктора

private http: HttpClient

// сервисный метод

getBook(): Observable<Book> {return this.http.get<Book>({url}, {options});}
5
Przemek Struciński 11 Окт 2017 в 09:26

Я думаю, вам следует объявить интерфейс Book вместо класса book:

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

К вашим услугам:

//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();
        });
5
dieuhd 28 Апр 2016 в 10:20