I wonder if someone can explain this error to me, since Im relatively new to angular, typescript and rxjs.
What I try to do is to map the server response I get for calling getHeroes()
in a format that makes it easy for my components to consume it.
This is my getHeroes()
method that is working:
getHeroes(): Observable<Hero[]> {
const heroes = this.http.get<any>(this.heroesUrl)
.pipe(
map((res: EmbeddedResponse) => res._embedded.heroes),
tap(data => this.log('HeroService: fetched Heroes'),
catchError(this.handleError<Hero[]>('getHeroes', []))
))
return heroes
}
Notice the any type argument in this.http.get<any>()
I would like to be more specific with the type argument in getHeroes()
:
getHeroes(): Observable<Hero[]> {
const heroes = this.http.get<Hero[]>(this.heroesUrl)
.pipe(
map((res: EmbeddedResponse) => res._embedded.heroes),
tap(data => this.log('HeroService: fetched Heroes'),
catchError(this.handleError<Hero[]>('getHeroes', []))
))
return heroes
}
Notice the Hero[] type argument in this.http.get<Hero[]>()
But changing the type argument in getHeroes()
from any -> Hero[] resolves in this Error:
error TS2345: Argument of type 'OperatorFunction<EmbeddedResponse, Hero[]>' is not assignable to parameter of type 'OperatorFunction<Hero[], Hero[]>'.
Property '_embedded' is missing in type 'Hero[]' but required in type 'EmbeddedResponse'.
The EmbeddedResponse interface looks like this:
interface EmbeddedResponse {
_embedded: {
heroes: Hero[]
}
}
The response from the server looks like this:
{
"_embedded" : {
"heroes" : [ {
"id" : 1,
"name" : "Dicke Berta",
"_links" : {
"self" : {
"href" : "http://localhost:8080/heroes/1"
},
"hero" : {
"href" : "http://localhost:8080/heroes/1"
}
}
}, {
"id" : 5,
"name" : "Cobra-Car",
"_links" : {
"self" : {
"href" : "http://localhost:8080/heroes/5"
},
"hero" : {
"href" : "http://localhost:8080/heroes/5"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/heroes"
},
"profile" : {
"href" : "http://localhost:8080/profile/heroes"
},
"search" : {
"href" : "http://localhost:8080/heroes/search"
}
}
}
CodePudding user response:
The return type you defined in get is only assigned to the get function itself, not the whole chain. You defined get to return type Hero[], but in map you expect it to be of type EmbeddedResponse. Instead define get to return EmbeddedResponse:
this.http.get<EmbeddedResponse>(this.heroesUrl)
Then you don´t even need to define the type for "res" in map, since that is then already defined (though you can also leave it for readability):
map((res) => res._embedded.heroes)
The return type of your chain is defined by the last element return something, in your case map. res._embedded.heroes is of type Hero[], therefore your const heroes will be of type Observable<Hero[]>.
Finally in tap and catchError you probably set your brackets wrong. catchError shouldn´t be a part of tap but rather chained after it:
tap(data => this.log('HeroService: fetched Heroes')),
catchError(this.handleError('getHeroes', []))
);
CodePudding user response:
Your catchError
operator should be inside pipe not inside tap
pipe(
map((res: EmbeddedResponse) => res._embedded.heroes),
tap(data => this.log('HeroService: fetched Heroes')),
catchError(this.handleError<Hero[]>('getHeroes', []))
))