Setting http option as 'responseType: 'text'' causes compile failure for a http post request with angular HttpClient

Viewed 6364

Although there is an overloaded API method in angular HttpClient as bellow:

 post(url: string, body: any | null, options: {
        headers?: HttpHeaders | {
            [header: string]: string | string[];
        };
        observe?: 'body';
        params?: HttpParams | {
            [param: string]: string | string[];
        };
        reportProgress?: boolean;
        responseType: 'text';
        withCredentials?: boolean;
    }): Observable<string>;

when I try to do bellow post request with the option 'responseType: 'text'' I get a compiler error stating "No overload matches this call. ..."

const opts = {
      headers: new HttpHeaders({
        'Accept': 'text/html, application/xhtml+xml, */*',
        'Content-Type': 'text/plain; charset=utf-8'
      }),
      responseType: 'text'
    };
    return this.http.post<string>('url', null, opts);

Note : I'm passing null as response body sensibly as my API doesn't accept a body. What I'm I doing possibly wrong here?

Update Adding the full error message as per the request by Michael D

Type 'Observable<ArrayBuffer>' is not assignable to type 'Observable<string>'.
  Type 'ArrayBuffer' is not assignable to type 'string'.ts(2322)
No overload matches this call.
  Overload 1 of 15, '(url: string, body: any, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe: "events"; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "json"; withCredentials?: boolean; }): Observable<...>', gave the following error.
    Argument of type '{ headers: HttpHeaders; responseType: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe: "events"; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "json"; withCredentials?: boolean; }'.
      Property 'observe' is missing in type '{ headers: HttpHeaders; responseType: string; }' but required in type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe: "events"; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "json"; withCredentials?: boolean; }'.
  Overload 2 of 15, '(url: string, body: any, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe: "response"; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "json"; withCredentials?: boolean; }): Observable<...>', gave the following error.
    Argument of type '{ headers: HttpHeaders; responseType: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe: "response"; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "json"; withCredentials?: boolean; }'.
      Property 'observe' is missing in type '{ headers: HttpHeaders; responseType: string; }' but required in type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe: "response"; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "json"; withCredentials?: boolean; }'.
  Overload 3 of 15, '(url: string, body: any, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "json"; withCredentials?: boolean; }): Observable<...>', gave the following error.
    Argument of type '{ headers: HttpHeaders; responseType: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "json"; withCredentials?: boolean; }'.
      Types of property 'responseType' are incompatible.
        Type 'string' is not assignable to type '"json"'.ts(2769)
http.d.ts(2293, 9): 'observe' is declared here.
http.d.ts(2409, 9): 'observe' is declared here.
4 Answers

The problem is with the responseType property. Assigning it as a string like this won't work straight away.

You can either cast it as a text type

const opts  = {
  headers: new HttpHeaders({
    'Accept': 'text/html, application/xhtml+xml, */*',
    'Content-Type': 'text/plain; charset=utf-8'
  }),
  responseType: 'text' as 'text' //<== here
};

    this.http.post(....);

Edit This will only work with using non generic version of http calls (this.http.post(...) but not generic versions this.http.post<string>)

Or, you can declare your options as any, this should stop the compiler from complaining

const opts : any = {
  headers: new HttpHeaders({
    'Accept': 'text/html, application/xhtml+xml, */*',
    'Content-Type': 'text/plain; charset=utf-8'
  }),
  responseType: 'text'
};

this.http.post<string>(....)

I think I've figured out the fault in my code thanks to this comment from reppners here The problems is that I'm trying to use generics type for the post() method call which is applicable only when the responseType is equal to 'json'. Have a look at the HttpClient's post method overloaded declarations bellow

post(url: string, body: any | null, options: {
        headers?: HttpHeaders | {
            [header: string]: string | string[];
        };
        observe?: 'body';
        params?: HttpParams | {
            [param: string]: string | string[];
        };
        reportProgress?: boolean;
        responseType: 'text';
        withCredentials?: boolean;
    }): Observable<string>;

 post<T>(url: string, body: any | null, options?: {
        headers?: HttpHeaders | {
            [header: string]: string | string[];
        };
        observe?: 'body';
        params?: HttpParams | {
            [param: string]: string | string[];
        };
        reportProgress?: boolean;
        responseType?: 'json';
        withCredentials?: boolean;
    }): Observable<T>;

Therefore bellow is the working code for my problem

 apiMethod(): Observable<string> {

    const options  = {
      headers: new HttpHeaders({
        'Accept': 'text/html, application/xhtml+xml, */*',
        'Content-Type': 'text/plain; charset=utf-8'
      }),
      responseType: 'text' as 'text'
  };
    return this.http.post('url', null, options);
  }

Although it is strange behavior. The options in HttpClient are not really of any type. It is customized for each overloading.

You will have to pass the options as a whole into the http call.

return this.http.post<string>('url', null, {
      headers: new HttpHeaders({
        'Accept': 'text/html, application/xhtml+xml, */*',
        'Content-Type': 'text/plain; charset=utf-8'
      }),
      responseType: 'text'
    });

Or as David suggested set the options type as any.

opts['responseType'] is inferred as string. Try responseType: 'text' as const or

const opts = {
   ...
} as const;
Related