Property 'json' does not exist on type 'Object'

Stylishcoder picture Stylishcoder · Sep 1, 2017 · Viewed 114.1k times · Source

I'm trying fetch data via REST with angular 2 HttpClient. I'm following the angular tutorial here https://angular.io/tutorial/toh-pt6 and under the Heroes and HTTP section you'll see this snippet of code used to fetch hero data via http.

getHeroes(): Promise<Hero[]> {
  return this.http.get(this.heroesUrl)
         .toPromise()
         .then(response => response.json().data as Hero[])
         .catch(this.handleError);
}

And below is a similar version I wrote in my application

fetch(startIndex: number, limit: number): Promise<Order[]> {
    let url = this.baseUrl + "&startIndex=" + startIndex + "&limit=" + limit;

    return this.http.get(url)
                .toPromise()
                .then(response => response.json().results as Order[])
                .catch(this.handleError);
}

I'm using InteliJ Idea and there's a red line on the call response.json() and even when I try to build using ng build I get the error.

Property 'json' does not exist on type 'Object'.

You may notice that instead of json().data I have json().results. That's because according to the tutorial the server responded with an object that has a data field but my own server responds with an object that has a results field. If you scroll down the tutorial a bit you'll see this point.

Note the shape of the data that the server returns. This particular in-memory web API example returns an object with a data property. Your API might return something else. Adjust the code to match your web API.

In an attempt to fix this, I tried something like this

(response: Response) => response.json().results as Order[]

When I did that the .json() method was been resolved but another error popped up that

Property results does not exist on type Promise

I tried fixing that by defining an interface

interface OrderResponse {
    orders: Order[];
}

And modified the get call to

 .get<OrderResponse>(url)...

But that also didn't work. Another error popped up

Type 'OrderResponse' is not assignable to type 'Response'.

One thing note is that, in the tutorial they used the Angular HttpModule but in my application I'm using the new Angular HttpClientModule so maybe that's where the error is coming.

I'm new to Angular 2 and this is the first app I'm building with it. If the above code is no longer valid with the new HttpClientModule I'd appreciate any help on how to achieve the same with the new HttpClientModule.

I found similar questions Property 'json' does not exist on type '{}' and Property does not exist on type 'object' but none of the answers there helped me.

Update

As the comments suggested there is no .json() method in the new HttpClientModule. I'd still appreciate help on how to achieve the same effect with the new module. From the guide they did something like this

http.get<ItemsResponse>('/api/items').subscribe(data => {
  // data is now an instance of type ItemsResponse, so you can do this:
  this.results = data.results;
});

Which I understand perfectly but my problem is, that code is not within a component but a service so calling subscribe and assigning the result to a instance field won't make much sense.

I need my service to return an array of Orders wrapped in a Promise. The my components can just make calls like

this.orderService.fetch(0, 10).then(orders => this.orders = orders)

I also thought of declaring a local variable in my service fetch method so that I can do

.subscribe(data => {
    this.orders = data.results;
}
// and out of the get call I return my local variable orders like
return Promise.resolve(orders)

But that doesn't make much sense to me as the call to .get() is asynchronous and the method may return even before all the data is fetch and the orders array may be empty.

Update

As requested here is the code for handleError

private handleError(error: any): Promise<any> {
    console.log('An error occured ', error);
    return Promise.reject(error.message || error);
}

Answer

Voicu picture Voicu · Dec 21, 2017

For future visitors: In the new HttpClient (Angular 4.3+), the response object is JSON by default, so you don't need to do response.json().data anymore. Just use response directly.

Example (modified from the official documentation):

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

@Component(...)
export class YourComponent implements OnInit {

  // Inject HttpClient into your component or service.
  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    this.http.get('https://api.github.com/users')
        .subscribe(response => console.log(response));
  }
}

Don't forget to import it and include the module under imports in your project's app.module.ts:

...
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    BrowserModule,
    // Include it under 'imports' in your application module after BrowserModule.
    HttpClientModule,
    ...
  ],
  ...