Property 'data' does not exist on type 

2019-01-28 16:31发布

问题:

I have a setup like this

  • api.service (wraps the httpClient Module)
  • customer.service

the api service get looks like this:

get<T>(url: string, options?) {
return this.httpClient.get<T>(this.apiUrl + url, this.getOptions(options));}

in my customer.service I have:

    private fetchCustomer(access_token: String): Observable<Customer> {
      const options = { headers: new HttpHeaders({ Authorization: 'Bearer ' + access_token }) };
      return this.http
        .get<Customer>('customers/me', options)
        .map(res => {
          const customer = res.data;
          customer.access_token = access_token;
          return customer;
        })
        .catch(this.handleError.bind(this));
    }

and it give me this error:

[ts]
Property 'data' does not exist on type 'HttpEvent<Customer>'.
Property 'data' does not exist on type 'HttpSentEvent'.

回答1:

Looking at the angular source code (v4.3.3), when you wrap the http.get without specifying the type of options the typescript compiler is using this type definition

/**
 * Construct a GET request which interprets the body as JSON and returns the full event stream.
 *
 * @return an `Observable` of all `HttpEvent`s for the request, with a body type of `T`.
 */
get<T>(url: string, options: {
    headers?: HttpHeaders;
    observe: 'events';
    params?: HttpParams;
    reportProgress?: boolean;
    responseType?: 'json';
    withCredentials?: boolean;
}): Observable<HttpEvent<T>>;

To get the typescript compiler to use the correct type definition, you can specify that the options is of type Object. In your case the getOptions method should specify it is returning the type Object.

get<T>(url: string, options?) {
    return this.httpClient.get<T>(
        this.apiUrl + url, 
        this.getOptions(options) // this.getOptions needs to specify it is returning the type Object
    );
}

getOptions(options): Object {...}

Now the typescript compiler will find the correct type definition

/**
 * Construct a GET request which interprets the body as JSON and returns it.
 *
 * @return an `Observable` of the body as type `T`.
 */
get<T>(url: string, options?: {
    headers?: HttpHeaders;
    observe?: 'body';
    params?: HttpParams;
    reportProgress?: boolean;
    responseType?: 'json';
    withCredentials?: boolean;
}): Observable<T>;

and finally now you can access data

const customer = res.data;


回答2:

The new HttpClient in Angular 4.3 has currently 3 protoypes for get<T>

They are

get<T>(url: string, options: {
    headers?: HttpHeaders;
    observe: 'events';
    params?: HttpParams;
    reportProgress?: boolean;
    responseType?: 'json';
    withCredentials?: boolean;
}): Observable<HttpEvent<T>>;

get<T>(url: string, options: {
    headers?: HttpHeaders;
    observe: 'response';
    params?: HttpParams;
    reportProgress?: boolean;
    responseType?: 'json';
    withCredentials?: boolean;
}): Observable<HttpResponse<T>>;

get<T>(url: string, options?: {
    headers?: HttpHeaders;
    observe?: 'body';
    params?: HttpParams;
    reportProgress?: boolean;
    responseType?: 'json';
    withCredentials?: boolean;
}): Observable<T>;

The Comments at the top of client.d.ts state this.

 * Each request method has multiple signatures, and the return type varies according to which
 * signature is called (mainly the values of `observe` and `responseType`).

The really important part is the observe parameter

get<T>(url, {observe: 'events'}) returns HttpEvent<T>

get<T>(url, {observe: 'response'}) returns HttpResponse<T>

get<T>(url, {observe: 'body'}) returns T


Note: if you subclass the options part into a method you must return a type of Object, without that the compiler will automatically select the first method which happens to return HttpEvent<T>

so

getOptions(): any {
    return { observe: 'body' }
};

and

getOptions(): any {
    return { observe: 'response' }
};

will compile to the wrong interface and return HttpEvent<T>, but

getOptions(): object {
    return { observe: 'body'}
};

and

getOptions(): object {
    return { observe: 'response'}
};

will return T and HttpResponse<T> respectively



回答3:

The solution is to use the new way of getting the json data....

const customer = res['data'];


回答4:

First convert the data to a javascript object using the json method. Then get the data you need using subscribe.

return this.http
        .get<Customer>('customers/me', options)
        .map(res => res.json())
        .subscribe(data => {
          const customer = res.data;
          customer.access_token = access_token;
          return customer;
        })
        .catch(this.handleError.bind(this));


标签: angular http get