Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript - .pipe(catchError()) type issues. #3673

Closed
RayLuxembourg opened this issue May 9, 2018 · 15 comments
Closed

Typescript - .pipe(catchError()) type issues. #3673

RayLuxembourg opened this issue May 9, 2018 · 15 comments

Comments

@RayLuxembourg
Copy link

RayLuxembourg commented May 9, 2018

source.pipe(catchError(e=>throwError(new Error("SOMETHING BAD HAPPENED"))))
source.subscribe((r:Author)=>console.log("GOOD"),err=>console.log("ERROR))

basically there is an issue with catchError because it will mess up with the type resulting in this error like this :

error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<Author>'.
  Type '{}' is not assignable to type 'Author'.
    Property 'title' is missing in type '{}'.

I created a work around this but maybe there is a better way.

  private catchHttpError = <T>() =>
    catchError<T, T>((error: HttpErrorResponse) => {
      const msg = `${error.status} ${error.statusText} -  ${error.url}`;

      return throwError(new Error(msg));
    });

  private apiPipe = <T>() => pipe(share(), this.catchHttpError<T>());

When i pass the type to my apiPipe function and to catchError operator no errors comeout but it looks dirty to me.

Anyone have ideas?

@wmild
Copy link

wmild commented May 9, 2018

I saw the same thing today.

@martinsik
Copy link
Contributor

I tested this on stackblitz and it doesn't show any compilation error.
https://stackblitz.com/edit/rxjs6-demo-xrqrva?file=index.ts

I tried it also locally with [email protected] and [email protected] and it compiled fine.

@RayLuxembourg
Copy link
Author

@martinsik this is very weird.

@sandrocsimas
Copy link

sandrocsimas commented May 18, 2018

The same here, but the problem seems to be with throwError.
Previously I had:

  public createAccount(name: string, email: string, password: string): Observable<Account> {
    return this.http.post<Account>(RequestUtils.getApiUrl('/accounts'), {name, email, password}, RequestUtils.getJsonOptions()).pipe(
      map((data: Account) => new Account(data)),
      catchError((err: HttpErrorResponse) => {
        const apiError = ApiError.withResponse(err);
        this.eventService.publish(EventService.EVENT_API_ERROR, apiError);
        return Observable.throw(apiError);
      })
    );
  }

It compiles but Observable.throw should be replaced by throwError. By replacing, Typescript is forcing me to return the Observable<{} | Account>.

  public createAccount(name: string, email: string, password: string): Observable<{} | Account> {
    return this.http.post<Account>(RequestUtils.getApiUrl('/accounts'), {name, email, password}, RequestUtils.getJsonOptions()).pipe(
      map((data: Account) => new Account(data)),
      catchError((err: HttpErrorResponse) => {
        const apiError = ApiError.withResponse(err);
        this.eventService.publish(EventService.EVENT_API_ERROR, apiError);
        return throwError(apiError);
      })
    );
  }

I don't want to return Observable<{} | Account>, but just Observable< Account >.

@sandrocsimas
Copy link

OK, It seems I was importing throwError wrongly.
From:
import {throwError} from 'rxjs/observable/throw';
To:
import {_throw} from 'rxjs/observable/throw';

@benlesh
Copy link
Member

benlesh commented May 21, 2018

  • What version of RxJS are you using?

@jdgarvey
Copy link

@benlesh
I'm running into this same problem with RxJs 6.1.0 and RxJS 5.x. Here is the code that is causing the errors for me:

  cartSetShippingAddress(sessionId: string, address: Address): Observable<string> {
    const url = `...`;

    const postData = {...};

    return this.http.post(url, postData).pipe(
      map((res: {addressId: string}) => res.addressId),
      catchError(this.handleError.bind(this))
    );
  }

And in the handleError method:

  private handleError(error) {
    let errMsg: string;
    ...
    return _throw(errMsg);
  }

The error that I get is:

error TS2322: Type 'Observable<string | {}>' is not assignable to type 'Observable<string>'.
  Type 'string | {}' is not assignable to type 'string'.
    Type '{}' is not assignable to type 'string'.

If I remove the catchError call, the error goes away, and if I change the return type of cartSetShippingAddress to Observable<string | {}>, the error also goes away.
I also tried returning something other than _throw(...) from the handleError method, but no matter what I return, the error persists.

@jdgarvey
Copy link

jdgarvey commented May 21, 2018

@benlesh
I've created a StackBlitz that shows the issue:
https://stackblitz.com/edit/angular-rxjs-typings?embed=1&file=src/app/example.service.ts.

@karstensgit
Copy link

karstensgit commented May 22, 2018

@jdgarvey i have edited your stackblitz to remove the compilation error. You have to typecast your http.get to "MyModel", otherwise it expects something of type "Object", which is not compliant with the methods return type. I also changed it back to the "throwError" method from 'rxjs' (note: no deep import with rxjs @^6.0.0), which i believe (correct me if im wrong) is the correct way to do it:

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {map, catchError} from 'rxjs/operators';
import {Observable, throwError} from 'rxjs';

interface MyModel {
  foo: string;
}

@Injectable()
export class ExampleService {
  constructor(private http: HttpClient) {}

  exampleGet(): Observable<MyModel> {
    return this.http.get<MyModel>('example/endpoint')
      .pipe(
        catchError(e => throwError(e))
      );
  }
}

I am not sure if this will fix the original question as well

@jdgarvey
Copy link

@karstensgit thank you for checking this out! I tried your code, and it fixed the StackBlitz. Then I ported that code over to my project and was still getting an error, but then realized it was because .bind wasn't being correctly typed. If anybody has this same problem, check this issue out. Once I included the correct types for .bind, the compilation errors went away.

As for proper way to import throw, I have seen it both ways. The most "official" way seems to be the way you described, but I cannot seem to import throwError from rxjs, I have to import it from rxjs/index. Strange, but I'll keep checking it out.

Thanks again for your help!

@martinsik
Copy link
Contributor

@jdgarvey What TypeScript version you used to compile your example?

@jdgarvey
Copy link

@martinsik My local project is using 2.6.2. Couldn't find TS version on the StackBlitz.

@benlesh
Copy link
Member

benlesh commented May 29, 2018

@jdgarvey your example is incorrectly trying to import _throw from rxjs/observable/throw in RxJS 6.1.0... it's import { throwError } from 'rxjs;` that you want to do.

You're actually not typing the return of this.http.get either:

this code compiles fine:

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {map, catchError} from 'rxjs/operators';
import {Observable, throwError} from 'rxjs';

interface MyModel {
  foo: string;
}

@Injectable()
export class ExampleService {
  constructor(private http: HttpClient) {}

  exampleGet(): Observable<MyModel> {
    return this.http.get<MyModel>('example/endpoint')
      .pipe(
        catchError(e => throwError(e))
      );
  }
}

@benlesh
Copy link
Member

benlesh commented May 29, 2018

Given that I haven't seen a minimal reproduction of this issue where some other typing wasn't incorrect, I'm going to close this issue.

Here's a minimal version of what people think is going on that does, in fact, compile:

import { Observable, of, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

const result: Observable<number> = of(1, 2, 3).pipe(
  catchError(err => throwError(new Error('lol'))),
);

If you hit this issue, you probably needed to properly type the source going into your catchError.

@benlesh benlesh closed this as completed May 29, 2018
@jdgarvey
Copy link

@benlesh thank you for the example, this works.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 28, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants