Search code examples
angularrxjsrxjs6angular13

RxJs catchError changes return type


I'm trying to implement some caching and I have the below method. The catchError block is causing an error because the return type becomes Observable<Client | Client[]>. I'm not seeing why it thinks it's not an array of client, or how to fix.

#clients: Client[] = []
#clientsLastModified: string | null = null


index(): Observable<Client[]> {
    let headers = new HttpHeaders()
    if (this.#clientsLastModified)
        headers = headers.set('If-Modified-Since', this.#clientsLastModified)

    return this.http.get<IClientDTO[]>('clients', {headers, observe: 'response'}).pipe(
        map(x => {
            this.#clientsLastModified = x.headers.get('Last-Modified')

            if (x.status === HttpStatusCode.Ok && x.body) {
                this.#clients = x.body.map(x => new Client(x))
                return this.#clients
            } else
                return of([])
        }),
        catchError((err: unknown) => {
            if (err instanceof HttpErrorResponse && err.status === HttpStatusCode.NotModified)
                return this.#clients

            return throwError(() => err)
        })
    )
}

Solution

  • There are two small changes to make to get this corrected:

    1. don't use of inside your map. You want the result of your map to return type Client[]; of makes it return Observable<Client[]>

    2. use of inside catchError. Inside catchError, you should return observable, so of is needed. The reason no error is shown is because the type is Array, and Array is also a vaild ObservableInput, but will have different behavior. RxJS will convert Array to an observable that emits each item individually (thus the type ends up being Observable<Client> instead of Observable<Client[]>).

    return this.http.get<IClientDTO[]>('clients', {headers, observe: 'response'}).pipe(
      map(x => {
        this.#clientsLastModified = x.headers.get('Last-Modified')
    
        if (x.status === HttpStatusCode.Ok && x.body) {
          this.#clients = x.body.map(x => new Client(x))
            return this.#clients
          } else
            return [] // <-- don't use of
      }),
      catchError((err: unknown) => {
        if (err instanceof HttpErrorResponse && err.status === HttpStatusCode.NotModified)
          return of(this.#clients) // <-- use of
    
          return throwError(() => err)
      })
    )