Angular 4/5 HttpClient:字符串类型的参数不可分配给 'body'

Angular 4/5 HttpClient: Argument of type string is not assignable to 'body'

Angular 文档说:

The response body doesn't return all the data you may need. Sometimes servers return special headers or status codes to indicate certain conditions, and inspecting those can be necessary. To do this, you can tell HttpClient you want the full response instead of just the body with the observe option:

http
  .get<MyJsonData>('/data.json', {observe: 'response'})
  .subscribe(resp => {
    // Here, resp is of type HttpResponse<MyJsonData>.
    // You can inspect its headers:
    console.log(resp.headers.get('X-Custom-Header'));
    // And access the body directly, which is typed as MyJsonData as requested.
    console.log(resp.body.someField);
  });

但是当我尝试这样做时,出现编译时错误(但没有运行时错误,按预期工作):

error TS2345: Argument of type '{ headers: HttpHeaders; observe: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'. Types of property 'observe' are incompatible. Type 'string' is not assignable to type '"body"'.

为什么?我用 "@angular/http": "^5.1.0"

这是我的代码版本:

  login(credentials: Credentials): Observable<any> {
    const options = {
      headers: new HttpHeaders({'Content-Type': 'application/json'}),
      observe: 'response'
    };
    return this.httpClient.post<any>(`${environment.USER_SERVICE_BASE_URL}`,
      {'username': credentials.username, 'password': credentials.password}, options)
      .map((res) => ...

您必须内联选项。请参阅 github ticket #18586alxhub 于 8 月 9 日发表的文章 2017.

Typescript needs to be able to infer the observe and responseType values statically, in order to choose the correct return type for get(). If you pass in an improperly typed options object, it can't infer the right return type.

login(credentials: Credentials): Observable<any> {
    return this.httpClient.post<any>(`${environment.USER_SERVICE_BASE_URL}`,
      {'username': credentials.username, 'password': credentials.password}, {
      headers: new HttpHeaders({'Content-Type': 'application/json'}),
      observe: 'response'
    })
      .map((res) => ...

在没有 inline-ing 选项(这可能导致代码不那么干净)的情况下,我解决这个问题的方法是为请求选项创建一个接口。代码如下所示:

export interface IRequestOptions {
    body?: any;
    headers?: HttpHeaders | { [header: string]: string | Array<string> };
    observe?: any;
    params?: HttpParams | { [param: string]: string | Array<string> };
    reportProgress?: boolean;
    responseType?: "arraybuffer" | "blob" | "json" | "text";
    withCredentials?: boolean;
}

然后这样使用:

const options: IRequestOptions = {
    headers: new HttpHeaders({"Content-Type": "application/json"}),
    observe: "response"
};
return this.httpClient.post(`${environment.USER_SERVICE_BASE_URL}`,
    {"username": credentials.username, "password": credentials.password}, options)
    .pipe(
        map((res: HttpResponse<any>) => ...
    );

将原来的 post 更改为使用 lettablepipeable(无论今天的名称是什么)运算符

Typescript 抱怨这个问题

Type 'string' is not assignable to type "body"

要解决此问题,请手动将字符串转换为正文。示例:

    const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json'
      }),
      observe: 'response' as 'body'
    };
    return this.http.post<any>(url, data, httpOptions);
import { HttpHeaders, HttpParams } from '@angular/common/http';
export interface IRequestOptions {
    headers?: HttpHeaders | { [header: string]: string | string[]; };
    observe: "response"; 
    params?: HttpParams | { [param: string]: string | string[]; };
    reportProgress?: boolean; 
    responseType?: "json";
    withCredentials?: boolean; 
}