33

I'm getting a compilation error on the return type when using HttpClient. In my function GetPortfolio, I'm expecting the GET call to return the json object of type Observable<Portfolio> but it's giving the error:

Type Observable<HttpEvent<Portfolio>> is not assignable to type Observable<Portfolio>. Type HttpEvent<Portfolio> is not assignable to type Portfolio. Type HttpProgressEvent is not assignable to type Portfolio. Property name is missing in type HttpProgressEvent.

My code:

import { Injectable } from '@angular/core';
import { environment } from './environments/environment';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';


export interface Portfolio {
  name: string;
  id: string;
}

@Injectable()
export class PortfolioService {

    private httpOptions;

    apiUrl: string;

    constructor(private http: HttpClient) {
      this.apiUrl = environment.apiUrl + "/api/portfolios";

      this.httpOptions = {
        headers: new HttpHeaders(
          {
            'Content-Type': 'application/json',
          })   
      };
    }


    GetPortfolio(portfolioId: string): Observable<Portfolio> {
      return this.http.get<Portfolio>(this.apiUrl + '/${portfolioId}', this.httpOptions);
   }

}

From the angular hero tutorial and docs HttpClient requests should expect Observable<any>: Angular HttpClient doc

So am I doing something wrong? Or should I be setting the return value to Observable<HttpEvent<Portfolio>> ?

roverred
  • 1,841
  • 5
  • 29
  • 46

6 Answers6

49

Typecast your httpOptions

private httpOptions: {
    headers: HttpHeaders
};

The typescript compiler is pulling the wrong get method type (src)

/**
* 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 | {[header: string]: string | string[]},
    observe: 'events',
    params?: HttpParams|{[param: string]: string | string[]},
    reportProgress?: boolean,
    responseType?: 'json',
    withCredentials?: boolean,
}): Observable<HttpEvent<T>>;

When you specify the type with headers, it pulls the correct type. (src)

/**
* 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 | {[header: string]: string | string[]},
    observe?: 'body',
    params?: HttpParams|{[param: string]: string | string[]},
    reportProgress?: boolean,
    responseType?: 'json',
    withCredentials?: boolean,
}): Observable<T>;
LLai
  • 13,128
  • 3
  • 41
  • 45
  • 1
    this was exactly my problem, the httpOption type for me was set up as 'any', as soon the type change to include headers typescript detect the correct 'get' method – Alejandro Silva Sep 12 '18 at 18:46
  • 6
    This was the answer for me, but this is just ridiculous. It makes the entire http client overly engineered and difficult to debug if you're not careful with how you type things. Instead of adding the http options on the spot, I placed them as a global provided value at the top of the app, so I can just simply inject and add to any request I want, overriding as needed. It was at the constructor that I didn't specify the type as '{headers:HttpHeaders}'. – OzzyTheGiant Oct 18 '18 at 16:35
  • Where did you come up with this? – Darin Cardin Jul 11 '23 at 20:19
  • @DarinCardin I went through the source code type files of angular (: – LLai Jul 13 '23 at 16:19
15

i solve this casting my header params like this

return this.http.get<SomeModel>(someUrl, <Object>this.options);
koutat cruzado
  • 151
  • 1
  • 3
8

It's strange, don't give error if you write

GetPortfolio(portfolioId: string): Observable<Portfolio> {
    return this.http.get<Portfolio>('....', {
        headers: new HttpHeaders(
            {
                'Content-Type': 'application/json',
            })   
    });
}

It's look like, the compiler expect an object with the properites headers,params,observe..., but as your object have no type, the compiler can accept it

even you can do

headers: HttpHeaders = new HttpHeaders({
        'Content-Type': 'application/json',
    })
GetPortfolio(portfolioId: string): Observable<Portfolio> {
        return this.http.get<Portfolio>('...', {
            headers: this.headers
        })
    }
Eliseo
  • 50,109
  • 4
  • 29
  • 67
2

As mentioned by various answers, in short:

your options have to be of type object instead of type any

Pipo
  • 4,653
  • 38
  • 47
0

As per Angular Great Docs

You can simply solve this by setting the observe in httpOptions to "response"

getConfigResponse(): Observable<HttpResponse<Config>> { return this.http.get<Config>( this.configUrl, { observe: 'response' }); }

this will return HttpResponse<Config> instead of Config only if we didn't set observe ='response'

Ahmed
  • 595
  • 4
  • 25
-1

As this is a service 'PortfolioService' we may not need interface here, instead we can use of type any, and also GET method is only necessary here.

GetPortfolio(portfolioId): Observable<any> {
  return this.http.get(this.apiUrl + '/${portfolioId}')
         .map((response:any) => {
              return response;
         });
}

This should work, please try.

nithalqb
  • 225
  • 1
  • 12
  • 3
    using `any` will deactivate the auto completion. –  Jan 23 '18 at 12:40
  • 1
    I'm not the OP, and yes it will work. I'm stating as information that this will deactivate auto completion. –  Jan 23 '18 at 12:43
  • 2
    yup the code does work. But I'd lose the explicit return type, which I'd preferably like to keep. – roverred Jan 23 '18 at 12:45