From 06f9183f15e6acbde86b86d5f8be36ac8cfaa9bc Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Fri, 15 Mar 2019 10:24:58 -0700 Subject: [PATCH] fix(race): better typings (#4643) - Actually accept other `ObservableInput` types (Promises, etc) - Fixes issue where TypeScript would complain when you tried to subscribe to a race between to Observable types. Fixes #4390 Fixes #4642 --- spec-dtslint/observables/race-spec.ts | 151 +++++++++++++++++--------- src/internal/observable/race.ts | 29 +++-- 2 files changed, 120 insertions(+), 60 deletions(-) diff --git a/spec-dtslint/observables/race-spec.ts b/spec-dtslint/observables/race-spec.ts index 805d8a6137..e31f1465f2 100644 --- a/spec-dtslint/observables/race-spec.ts +++ b/spec-dtslint/observables/race-spec.ts @@ -5,65 +5,116 @@ it('should infer correctly with 1 parameter', () => { const o = race(a); // $ExpectType Observable }); -it('should infer correctly with multiple parameters of the same type', () => { - const a = of(1); - const b = of(2); - const o = race(a, b); // $ExpectType Observable -}); +describe('race(a, b, c)', () => { + it('should infer correctly with multiple parameters of the same type', () => { + const a = of(1); + const b = of(2); + const o = race(a, b); // $ExpectType Observable + }); -it('should support 2 parameters with different types', () => { - const a = of(1); - const b = of('a'); - const o = race(a, b); // $ExpectType Observable | Observable -}); + it('should support 2 parameters with different types', () => { + const a = of(1); + const b = of('a'); + const o = race(a, b); // $ExpectType Observable + }); -it('should support 3 parameters with different types', () => { - const a = of(1); - const b = of('a'); - const c = of(true); - const o = race(a, b, c); // $ExpectType Observable | Observable | Observable -}); + it('should support 3 parameters with different types', () => { + const a = of(1); + const b = of('a'); + const c = of(true); + const o = race(a, b, c); // $ExpectType Observable + }); -it('should support 4 parameters with different types', () => { - const a = of(1); - const b = of('a'); - const c = of(true); - const d = of([1, 2, 3]); - const o = race(a, b, c, d); // $ExpectType Observable | Observable | Observable | Observable -}); + it('should support 4 parameters with different types', () => { + const a = of(1); + const b = of('a'); + const c = of(true); + const d = of([1, 2, 3]); + const o = race(a, b, c, d); // $ExpectType Observable + }); -it('should support 5 parameters with different types', () => { - const a = of(1); - const b = of('a'); - const c = of(true); - const d = of([1, 2, 3]); - const e = of(['blah']); - const o = race(a, b, c, d, e); // $ExpectType Observable | Observable | Observable | Observable | Observable -}); + it('should support 5 parameters with different types', () => { + const a = of(1); + const b = of('a'); + const c = of(true); + const d = of([1, 2, 3]); + const e = of(['blah']); + const o = race(a, b, c, d, e); // $ExpectType Observable + }); -it('should support 6 or more parameters of the same type', () => { - const a = of(1); - const o = race(a, a, a, a, a, a, a, a, a, a, a, a, a, a); // $ExpectType Observable + it('should support 6 or more parameters of the same type', () => { + const a = of(1); + const o = race(a, a, a, a, a, a, a, a, a, a, a, a, a, a); // $ExpectType Observable + }); + + it('should return {} for 6 or more arguments of different types', () => { + const a = of(1); + const b = of('a'); + const c = of(true); + const d = of([1, 2, 3]); + const e = of(['blah']); + const f = of({ foo: 'bar' }); + const o = race(a, b, c, d, e, f); // $ExpectType Observable<{}> + }); }); -it('should return {} for 6 or more arguments of different types', () => { - const a = of(1); - const b = of('a'); - const c = of(true); - const d = of([1, 2, 3]); - const e = of(['blah']); - const f = of({ foo: 'bar' }); - const o = race(a, b, c, d, e, f); // $ExpectType Observable<{}> +describe('race([a, b, c])', () => { + it('should infer correctly with multiple parameters of the same type', () => { + const a = of(1); + const b = of(2); + const o = race([a, b]); // $ExpectType Observable + }); + + it('should support 2 parameters with different types', () => { + const a = of(1); + const b = of('a'); + const o = race([a, b]); // $ExpectType Observable + }); + + it('should support 3 parameters with different types', () => { + const a = of(1); + const b = of('a'); + const c = of(true); + const o = race([a, b, c]); // $ExpectType Observable + }); + + it('should support 4 parameters with different types', () => { + const a = of(1); + const b = of('a'); + const c = of(true); + const d = of([1, 2, 3]); + const o = race([a, b, c, d]); // $ExpectType Observable + }); + + it('should support 5 parameters with different types', () => { + const a = of(1); + const b = of('a'); + const c = of(true); + const d = of([1, 2, 3]); + const e = of(['blah']); + const o = race([a, b, c, d, e]); // $ExpectType Observable + }); + + it('should support 6 or more parameters of the same type', () => { + const a = of(1); + const o = race([a, a, a, a, a, a, a, a, a, a, a, a, a, a]); // $ExpectType Observable + }); + + it('should return {} for 6 or more arguments of different types', () => { + const a = of(1); + const b = of('a'); + const c = of(true); + const d = of([1, 2, 3]); + const e = of(['blah']); + const f = of({ foo: 'bar' }); + const o = race([a, b, c, d, e, f]); // $ExpectType Observable<{}> + }); }); -it('should handle an array of observables', () => { - const a = of(1); - const b = of(2); - const o = race([a, b]); // $ExpectType Observable +it('should race observable inputs', () => { + const o = race(of(1), Promise.resolve('foo'), [true, false]); // $ExpectType Observable }); -it('should return {} for array of observables of different types', () => { - const a = of(1); - const b = of('test'); - const o = race([a, b]); // $ExpectType Observable<{}> +it('should race an array observable inputs', () => { + const o = race([of(1), Promise.resolve('foo'), [true, false]]); // $ExpectType Observable }); diff --git a/src/internal/observable/race.ts b/src/internal/observable/race.ts index 7a1015c02f..c2c178c6d6 100644 --- a/src/internal/observable/race.ts +++ b/src/internal/observable/race.ts @@ -4,22 +4,31 @@ import { fromArray } from './fromArray'; import { Operator } from '../Operator'; import { Subscriber } from '../Subscriber'; import { Subscription } from '../Subscription'; -import { TeardownLogic } from '../types'; +import { TeardownLogic, ObservableInput } from '../types'; import { OuterSubscriber } from '../OuterSubscriber'; import { InnerSubscriber } from '../InnerSubscriber'; import { subscribeToResult } from '../util/subscribeToResult'; // tslint:disable:max-line-length -export function race(a: Observable, b: Observable): Observable | Observable; -export function race(a: Observable, b: Observable, c: Observable): Observable | Observable | Observable; -export function race(a: Observable, b: Observable, c: Observable, d: Observable): Observable | Observable | Observable | Observable; -export function race(a: Observable, b: Observable, c: Observable, d: Observable, e: Observable): Observable | Observable | Observable | Observable | Observable; +export function race(arg: [ObservableInput]): Observable; +export function race(arg: [ObservableInput, ObservableInput]): Observable; +export function race(arg: [ObservableInput, ObservableInput, ObservableInput]): Observable; +export function race(arg: [ObservableInput, ObservableInput, ObservableInput, ObservableInput]): Observable; +export function race(arg: [ObservableInput, ObservableInput, ObservableInput, ObservableInput, ObservableInput]): Observable; +export function race(arg: ObservableInput[]): Observable; +export function race(arg: ObservableInput[]): Observable<{}>; + +export function race(a: ObservableInput): Observable; +export function race(a: ObservableInput, b: ObservableInput): Observable; +export function race(a: ObservableInput, b: ObservableInput, c: ObservableInput): Observable; +export function race(a: ObservableInput, b: ObservableInput, c: ObservableInput, d: ObservableInput): Observable; +export function race(a: ObservableInput, b: ObservableInput, c: ObservableInput, d: ObservableInput, e: ObservableInput): Observable; // tslint:enable:max-line-length -export function race(observables: Observable[]): Observable; -export function race(observables: Observable[]): Observable<{}>; -export function race(...observables: Observable[]): Observable; -export function race(...observables: Observable[]): Observable<{}>; +export function race(observables: ObservableInput[]): Observable; +export function race(observables: ObservableInput[]): Observable<{}>; +export function race(...observables: ObservableInput[]): Observable; +export function race(...observables: ObservableInput[]): Observable<{}>; /** * Returns an Observable that mirrors the first source Observable to emit an item. @@ -50,7 +59,7 @@ export function race(...observables: Observable[]): Observable<{}>; * @name race * @owner Observable */ -export function race(...observables: (Observable[] | Observable)[]): Observable { +export function race(...observables: ObservableInput[]): Observable { // if the only argument is an array, it was most likely called with // `race([obs1, obs2, ...])` if (observables.length === 1) {