Home > Blockchain >  mapping http response to object array in type argument
mapping http response to object array in type argument

Time:10-15

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', []))
))

Demo

  • Related