问题
I have the following piece of code which works correctly.
public createData(data:Data):Observable<any>{
console.log('contacting server at '+this.API_URL +this.NEW_DATA_URL +" with data "+data+ " with httpOptions "+httpOptions.withCredentials + ","+httpOptions.headers );
let newData = new Data(data)
let body = JSON.stringify(newQuestion);
//I WANT TO MOVE THE CODE BELOW INTO A FUNCTION BUT AM GETTING COMPILATION ERROR
this.loaderService.show();
return this.http.post(this.NEW_QUESTION_URL,body,httpOptions)
.pipe(tap(response => {
let httpEvent = <HttpEvent<any>>response;
if(httpEvent.type === HttpEventType.Response)
{
console.log('response from backend service:', response);
return result;
}
else {
console.log("not an http response")
return response;
}
})
,catchError(this.handleError)
,finalize(()=> this.loaderService.hide())); //error handler if Observable fails
}
As I can reuse some part of the code, I thought to create a function but now I am getting compilation errors. I am unable to find out what is the mistake.
The new function is
private sendMessage(url:string, body:any,httpOptions:any){
this.loaderService.show();
return this.http.post(url,body,httpOptions)
.pipe(tap(response => {
let httpEvent = <HttpEvent<any>>response; //ERROR HERE - 'ArrayBuffer' cannot be converted to type 'HttpEvent<any>'.
if(httpEvent.type === HttpEventType.Response)
{
console.log('response from backend service:', response);
let result = <HttpResponse<any>>response;
return result;
}
else {
console.log("not an http response")
return response;
}
})
,catchError(this.handleError)
,finalize(()=> this.loaderService.hide())); //error handler if Observable fails
}
ERROR is
ERROR in src/app/web-to-backend-interface.service.ts(264,27): error TS2352:
Type 'ArrayBuffer' cannot be converted to type 'HttpEvent<any>'.
Type 'ArrayBuffer' is not comparable to type 'HttpUserEvent<any>'.
Property 'type' is missing in type 'ArrayBuffer'.
http.post
has several overloaded methods and one of them return Observable - angular.io/api/common/http/HttpClient#post. How do I make Angular use the overloaded version which returns Observable<T>
? I changed the code and added responseType:'json'
but that didnt work either
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
withCredentials: true,
observe: 'response' as 'response',
responseType: 'json'
};
let observable:Observable<HttpEvent<any>> = this.http.post(url,body,httpOptions)
return observable.pipe(tap((httpEvent:HttpEvent<any>) => {....}
The errors I am seeing are
ERROR in src/app/web-to-backend-interface.service.ts(80,71): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: 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 '"response"' is not assignable to type '"body"'.
src/app/web-to-backend-interface.service.ts(111,52): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: 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 '"response"' is not assignable to type '"body"'.
src/app/web-to-backend-interface.service.ts(195,73): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
src/app/web-to-backend-interface.service.ts(215,72): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
src/app/web-to-backend-interface.service.ts(250,54): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
src/app/web-to-backend-interface.service.ts(290,9): error TS2322: Type 'Observable<ArrayBuffer>' is not assignable to type 'Observable<HttpEvent<any>>'.
Type 'ArrayBuffer' is not assignable to type 'HttpEvent<any>'.
Type 'ArrayBuffer' is not assignable to type 'HttpUserEvent<any>'.
Property 'type' is missing in type 'ArrayBuffer'.
src/app/web-to-backend-interface.service.ts(296,59): error TS2552: Cannot find name 'response'. Did you mean 'Response'?
Why does making a separate function of a working code makes it non-compilable? What is my mistake?
回答1:
While I can't answer why you'd be getting a TS error now when you weren't before, I can advise you how to get rid of it (assuming the code was previously working before you refactored it). If you give response
a type on declaration, then it won't get an assumed type that you have to try and map:
.pipe(tap((response: HttpEvent<any>) => {
let httpEvent = response; // No need for type-casting here anymore.
回答2:
i was able to solve it but now I am left with more questions than answers. Would appreciate if someone could explain the behaviour to me.
I was using the following httpOptions
object
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
withCredentials: true,
observe: 'response' as 'response',
};
as was using it as follows in some places in the code.
return this.http.post(this.SIGNUP_USER_URL,body,httpOptions)
This worked.
Then I thought of changing the http.post
into a function sendMessage
(as explained in the question) and replaced it in only once place (remember I am using this.http.post
in several places so wanted to try it at one place to begin with). I noticed that using httpOptions
made post
return Observable<ArrayBuffer>
.
Doubt 1 - why?
Then I changed httpOptions
to
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
withCredentials: true,
observe: 'response' as 'response',
responseType:'json'
};
It started giving me errors at places where I am using http.post
directly (without sendMessage
. The error was
ERROR in src/app/web-to-backend-interface.service.ts(81,71): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: 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 '"response"' is not assignable to type '"body"'.
src/app/web-to-backend-interface.service.ts(112,52): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: 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 '"response"' is not assignable to type '"body"'.
src/app/web-to-backend-interface.service.ts(196,73): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
src/app/web-to-backend-interface.service.ts(216,72): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
src/app/web-to-backend-interface.service.ts(251,54): error TS2345: Argument of type '{ headers: HttpHeaders; withCredentials: boolean; observe: "response"; responseType: string; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
src/app/web-to-backend-interface.service.ts(291,9): error TS2322: Type 'Observable<ArrayBuffer>' is not assignable to type 'Observable<HttpEvent<any>>'.
Type 'ArrayBuffer' is not assignable to type 'HttpEvent<any>'.
Type 'ArrayBuffer' is not assignable to type 'HttpUserEvent<any>'.
Property 'type' is missing in type 'ArrayBuffer'.
So I removed responseType:'json'
from httpOptions
and added an explicit object in this.http.post
in my sendMessage
which worked!
private sendMessage(url:string, body:any,httpOptions){
...
let observable:Observable<HttpEvent<any>> = this.http.post(url,body,{
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
withCredentials: true,
observe: 'events',
responseType: 'json'
})
...
}
there seem to be relationship between observe and responseType. Eg observe=body and responseType=text means that post should observe (look in) the body, interpret it as text and return Observable. But I wonder why I just couldn't change httpOptions
来源:https://stackoverflow.com/questions/51854143/unable-to-compile-a-code-when-converted-into-a-function