1
votes

I am attempting to update some Angular 4 /rxjs code to use the new version 5 syntax and am running into some trouble.

Original Import Statements:

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import Properties from './properties';
import ErrorHandler from './error-handler';

//From vendor.ts
import 'rxjs/Subject'
import 'rxjs/BehaviorSubject';
import 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/timeoutWith';
import 'rxjs/add/operator/retryWhen';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/publishReplay';
import 'rxjs/Subscription';

Original Code:

downloadStatus(job : DownloadJob) : Observable<DownloadJob> {
    let params = {"jobId": job.id};
    return this.http.post(Properties.URLS.core.downloadStatus.href, params, this.getOptions())
                .retryWhen((errors) => {
                    return errors.mergeMap((error) => (error.status === 404) ? Observable.of(error) : Observable.throw(error))
                                    .delay(Properties.SETTINGS.download.pollInterval);
                })
                .timeoutWith(Properties.SETTINGS.download.timeout, Observable.of<DownloadJob>(job))
                .map(this.extractData).catch(ErrorHandler.handleError);
}

Updated Import Statements:

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { map, catchError, retryWhen, timeoutWith, flatMap, mergeMap, delay } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
import Properties from './properties';
import ErrorHandler from './error-handler';
//From vendor.ts
import 'rxjs/Subject'
import 'rxjs/BehaviorSubject';
import 'rxjs/Observable';
import 'rxjs/operators/catchError';
import 'rxjs/operators/filter';
import 'rxjs/operators/map';
import 'rxjs/operators/switchMap';
import 'rxjs/operators/mergeMap';
import 'rxjs/operators/debounceTime';
import 'rxjs/operators/timeoutWith';
import 'rxjs/operators/retryWhen';
import 'rxjs/operators/delay';
import 'rxjs/operators/distinctUntilChanged';
import 'rxjs/operators/publishReplay';
import 'rxjs/observable/of';
import 'rxjs/Subscription';

Updated Code:

downloadStatus(job : DownloadJob) : Observable<DownloadJob> {
    let params = {"jobId": job.id};
    return this.http.post(Properties.URLS.core.downloadStatus.href, params, this.getOptions()).pipe(
                retryWhen((errors) => {
                    return errors.pipe(
                                mergeMap((error) => (error.status === 404) ? of(error) : Observable.throw(error)),
                                delay(Properties.SETTINGS.download.pollInterval)
                    );
                }),
                timeoutWith(Properties.SETTINGS.download.timeout, of(job)),
                map(this.extractData),
                catchError(ErrorHandler.handleError)
    );
}

Error Message:

TS2345: Argument of type 'UnaryFunction<Observable<DownloadJob>, Observable<DownloadJob>>' is not assignable to parameter of type 'UnaryFunction<Observable<Response>, Observable<DownloadJob>>'.
  Types of parameters 'source' and 'source' are incompatible.
    Type 'Observable<Response>' is not assignable to type 'Observable<DownloadJob>'.
      Type 'Response' is not assignable to type 'DownloadJob'.
        Property 'id' is missing in type 'Response'.

The problem I am having is with the conversion from Observable.of(job) in the timeoutWith function to of(job). The TypeScript compiler is now (understandably) complaining about being able to assign the object type.

With this new syntax how to I fix that?

Thanks in advance!

2
where are you importing 'of' from ?Jota.Toledo
import { of } from 'rxjs/observable/of';khpremier
Post all the relevant code (imports included), and the exact and complete error you get.JB Nizet

2 Answers

2
votes

It looks like you need a map(response => response.json() as DownloadJob) somewhere (likely before retryWhen()).

It makes sense that it complains about post() returning Observable<Response>, and timeoutWith() returning DownloadJob.

You didn't see the problem before because the typing of the old prototype-style timeoutWith was wrong. It was still showing the return type as Observable<Response> and ignoring the type of the argument passed to it.

0
votes

I think I found a work around. I am a little new to the rxjs and Observable, but I think this is equivalent:

downloadStatus(job : DownloadJob) : Observable<DownloadJob> {
    let params = {"jobId": job.id};
    return this.http.post(Properties.URLS.core.downloadStatus.href, params, this.getOptions()).pipe(
                retryWhen((errors) => {
                    return errors.pipe(
                                mergeMap((error) => (error.status === 404) ? of(error) : Observable.throw(error)),
                                delay(Properties.SETTINGS.download.pollInterval)
                    );
                }),
                timeoutWith(Properties.SETTINGS.download.timeout,
                            Observable.create(observer => {
                                observer.next(job);
                                observer.complete();
                            })),
                map(this.extractData),
                catchError(ErrorHandler.handleError)
    );