Search code examples
angulartypescriptrxjsangular2-observables

RxJS observables and generic types for Angular2(Typescript) http wrapper


Today I encountered the following problem while trying to implement an abstract http service. This service should be base to extend for all other http services.

The implementation is following so far, skipping other methods for ilustration:

@Injectable()
export abstract class HttpWrapper<T> {

  private options: RequestOptions;

  constructor(private http: Http, private endpointUrl: string) {
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
    this.options = new RequestOptions({ headers: headers });
  }

  public getAll(): Observable<T[]>{
    return this.http.get(this.endpointUrl, this.options)
      .map(this.extractAll)
      .catch(this.handleError);
  }

  abstract handleError(error: any):Observable<Response>;

  abstract extractOne(res: Response):T;

  abstract extractAll(res: Response):T[];
}

Now if i want to use the abstract HttpWrapper i do the following:

@Injectable()
export class BlastReportService extends  HttpWrapper<Item> {

  constructor(http: Http) {
    super(http,'/api/items');
  }


  handleError(error: any):Observable<Response>{
    //Handling error
    return Observable.throw(error);
  }

  extractAll(res: Response):Item[]{
    let body = res.json();

    let formatedBody = body.map((item: Item) => {
      item = new Item(item);
      return blastReport;
    });

    return formatedBody || [{}];
  }
}

But doing this I get following compilation error:

Type 'Observable<Response>' is not assignable to type 'Observable<T[]>'.
  Type 'Response' is not assignable to type 'T[]'.
    Property 'find' is missing in type 'Response'.

I can't wrap my head around this because the method extractAll clearly returns Item[] and is used while mapping the results returned from the server.

I decided to implement this abstract HttpWrapper "to stay DRY". I'm not sure if it's the best way to do so.


Solution

  • It looks like the problem here is that handleError() returns an Observable<Reponse>, and therefore cannot be the return value of getAll() which expects an Observable<T[]>

    Changing the return type of handleError to Observable<T[]> should fix the issue.

    In HttpWrapper

    abstract handleError(error: any):Observable<T[]>
    

    In BlastReportService

    handleError(error: any): Observable<T[]> {
      return Observable.throw(error)
    }