Skip to content

Commit

Permalink
fix(types): support union type returns from catchError
Browse files Browse the repository at this point in the history
  • Loading branch information
benlesh committed Jan 9, 2019
1 parent 32d35fd commit 8350622
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 6 deletions.
10 changes: 9 additions & 1 deletion spec-dtslint/operators/catchError-spec.ts
@@ -1,10 +1,14 @@
import { of, Observable } from 'rxjs';
import { of, Observable, EMPTY } from 'rxjs';
import { catchError } from 'rxjs/operators';

it('should infer correctly', () => {
const o = of(1, 2, 3).pipe(catchError((() => of(4, 5, 6)))); // $ExpectType Observable<number>
});

it('should handle empty (never) appropriately', () => {
const o = of(1, 2, 3).pipe(catchError(() => EMPTY));
});

it('should infer correctly when not returning', () => {
const o = of(1, 2, 3).pipe(catchError((() => { throw new Error('your hands in the air'); }))); // $ExpectType Observable<number>
});
Expand All @@ -24,3 +28,7 @@ it('should enforce that selector returns an Observable', () => {
it('should enforce type of caught', () => {
const o = of(1, 2, 3).pipe(catchError((err, caught: Observable<string>) => of('a', 'b', 'c'))); // $ExpectError
});

it('should handle union types', () => {
const o = of(1, 2, 3).pipe(catchError(err => err.message === 'wee' ? of('fun') : of(123))); // $ExpectType Observable<string | number>
});
13 changes: 8 additions & 5 deletions src/internal/operators/catchError.ts
Expand Up @@ -5,10 +5,11 @@ import {Observable} from '../Observable';
import {OuterSubscriber} from '../OuterSubscriber';
import { InnerSubscriber } from '../InnerSubscriber';
import {subscribeToResult} from '../util/subscribeToResult';
import {ObservableInput, OperatorFunction, MonoTypeOperatorFunction} from '../types';
import {ObservableInput, OperatorFunction, MonoTypeOperatorFunction, ObservedValueOf} from '../types';

export function catchError<T>(selector: (err: any, caught: Observable<T>) => never): MonoTypeOperatorFunction<T>;
export function catchError<T, R>(selector: (err: any, caught: Observable<T>) => ObservableInput<R>): OperatorFunction<T, T | R>;
/* tslint:disable:max-line-length */
export function catchError<T, O extends ObservableInput<any>>(selector: (err: any, caught: Observable<T>) => O): OperatorFunction<T, T | ObservedValueOf<O>>;
/* tslint:enable:max-line-length */

/**
* Catches errors on the observable to be handled by returning a new observable or throwing an error.
Expand Down Expand Up @@ -77,8 +78,10 @@ export function catchError<T, R>(selector: (err: any, caught: Observable<T>) =>
* catch `selector` function.
* @name catchError
*/
export function catchError<T, R>(selector: (err: any, caught: Observable<T>) => ObservableInput<R>): OperatorFunction<T, T | R> {
return function catchErrorOperatorFunction(source: Observable<T>): Observable<T | R> {
export function catchError<T, O extends ObservableInput<any>>(
selector: (err: any, caught: Observable<T>) => O
): OperatorFunction<T, T | ObservedValueOf<O>> {
return function catchErrorOperatorFunction(source: Observable<T>): Observable<T | ObservedValueOf<O>> {

This comment has been minimized.

Copy link
@gudzdanil

gudzdanil Apr 16, 2019

https://i.imgur.com/EcHhHT1.jpg
this union type breaks validity of explicit typings

const operator = new CatchOperator(selector);
const caught = source.lift(operator);
return (operator.caught = caught as Observable<T>);
Expand Down

0 comments on commit 8350622

Please sign in to comment.