Angular HttpClient Methods not casting response ty

2020-03-07 05:27发布

问题:

Just started using the new HttpClient but whenever I make a call the response is not cast with the provided type. I tried both an interface and a class. Now I assume you can only use interface to cast to a response since that's the only example we see in the docs.

I rather use a class to have some helper functions in the model. Is there a way to achieve this that way?

--component

export class InvoicesComponent implements OnInit{    
invoices;

constructor(private invoiceService: InvoiceService){}

ngOnInit() {
   this.invoiceService.index()
   .subscribe(
       (invoices) => {
           console.log(this.invoices);
       }
    );
}

--service class
export class InvoiceService {
constructor(private api :HttpClient) {}   

  index() {
    return this.api.get<Array<Invoice>>('/invoices');
  }
}

 --interface

import { Customer } from "./Customer";
import { Payment } from "./Payment";

export interface IInvoice{
id: number;
user_id: number;
number: string;
cost: number;
status: number;
customer: Array<Customer>;
payments: Array<Payment>;
created_at: Date;

updated_at: Date;
deleted_at: Date;
}

回答1:

Is there a way to achieve this that way?

HttpClient cannot know how to instantiate a class for the returned data. You need to do this yourself:

const invoices$ = this.http.get('/invoices')
  .map(data => data.map(invoice => new Invoice(invoice)));

This assumes your Invoice class has a constructor which takes the data returned by the API endpoint to create an instance.

There is no actual »casting« going on here. It's called type assertions in Typescript because it only affects the type information. This can be seen with this simple example:

const value1: any = 42;
const value2: string = value1 as string;
console.log(typeof value2); // 'number'

value2 will be (incorrectly) typed as a string, but it is still a number and calling string methods on it will make the Typescript compiler happy, but cause an error at runtime.



回答2:

You can achieve it by inheritance like this:

this.http.get<Invoice[]>(...)
    .pipe(Invoice.serializeResponseMap());

class definition:

export class Invoice extends SerializableMap {
    static instanceType = Invoice;

    ...

    constructor() { super(); }

    ...
}


class SerializableMap {
  static instanceType: any;

  static serializeResponseMap(): any {
    const createInstance = (r) => {
      return Object.assign(new this.instanceType(), r);
    };

    return map((respValue: any) => {
      if (Array.isArray(respValue)) {
        return respValue.map(r => createInstance(r));
      }
      return createInstance(respValue);
    });
  }
}


标签: angular