Angular HttpClient return expecting observable<HttpEvent<any> rather than observable<any>
Asked Answered
V

6

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>> ?

Vitrics answered 23/1, 2018 at 12:1 Comment(7)
your return type is correctSigrid
If you expect your POST request to return something, could you please post the code of your POST request, and not your GET ?Ephrayim
@trichetriche sorry that was a mistake.I meant to say GETVitrics
Okay, then your code seems correct. This issue is common to interceptors, do you have any ?Ephrayim
@trichetriche nope, haven't added any interceptorsVitrics
Okay, last question, did you try with a class instead of an interface ?Ephrayim
@trichetriche yup, it's the same issueVitrics
S
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
        })
    }
Sekyere answered 23/1, 2018 at 14:5 Comment(2)
What is customHttp?Merchantable
I'm sorry, I edited. (I was doing tests with a service of my own in my own project)Sekyere
C
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>;
Canterbury answered 23/1, 2018 at 15:14 Comment(4)
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' methodPoser
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}'.Serpens
Where did you come up with this?Olomouc
@DarinCardin I went through the source code type files of angular (:Canterbury
D
16

i solve this casting my header params like this

return this.http.get<SomeModel>(someUrl, <Object>this.options);
Djebel answered 30/1, 2019 at 17:5 Comment(1)
Great thanks. You actually need to do this.options as object now.Jo
S
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
        })
    }
Sekyere answered 23/1, 2018 at 14:5 Comment(2)
What is customHttp?Merchantable
I'm sorry, I edited. (I was doing tests with a service of my own in my own project)Sekyere
S
3

As mentioned by various answers, in short:

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

Sebrinasebum answered 2/1, 2021 at 13:26 Comment(0)
K
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'

Kastroprauxel answered 2/2, 2022 at 5:47 Comment(0)
E
-2

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.

Endorsement answered 23/1, 2018 at 12:31 Comment(3)
using any will deactivate the auto completion.Ephrayim
I'm not the OP, and yes it will work. I'm stating as information that this will deactivate auto completion.Ephrayim
yup the code does work. But I'd lose the explicit return type, which I'd preferably like to keep.Vitrics

© 2022 - 2024 — McMap. All rights reserved.