Skip to content

Commit

Permalink
fix(combineLatest): improve typings for combineLatest (#4470)
Browse files Browse the repository at this point in the history
* fix(combineLatest): improve typings for combineLatest

Existing typings did a poor job of getting proper types from code that passed an array of observables or observable inputs to combineLatest. This issue was caught while trying master in google3. This resolves that issue.

* fixup! fix(combineLatest): improve typings for combineLatest
  • Loading branch information
benlesh authored Jan 15, 2019
1 parent 0042846 commit 40c3d9f
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 5 deletions.
60 changes: 60 additions & 0 deletions spec-dtslint/observables/combineLatest-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,63 @@ it('should accept 6 params and a result selector', () => {
it('should accept 7 or more params and a result selector', () => {
const o = combineLatest(a, b, c, d, e, f, g, g, g, () => new A()); // $ExpectType Observable<A>
});

it('should accept 1 param', () => {
const o = combineLatest([a]); // $ExpectType Observable<[A]>
});

it('should accept 2 params', () => {
const o = combineLatest([a, b]); // $ExpectType Observable<[A, B]>
});

it('should accept 3 params', () => {
const o = combineLatest([a, b, c]); // $ExpectType Observable<[A, B, C]>
});

it('should accept 4 params', () => {
const o = combineLatest([a, b, c, d]); // $ExpectType Observable<[A, B, C, D]>
});

it('should accept 5 params', () => {
const o = combineLatest([a, b, c, d, e]); // $ExpectType Observable<[A, B, C, D, E]>
});

it('should accept 6 params', () => {
const o = combineLatest([a, b, c, d, e, f]); // $ExpectType Observable<[A, B, C, D, E, F]>
});

it('should have basic support for 7 or more params', () => {
const o = combineLatest([a, b, c, d, e, f, g]); // $ExpectType Observable<(A | B | C | D | E | F | G)[]>
});

it('should handle an array of Observables', () => {
const o = combineLatest([a, a, a, a, a, a, a, a, a, a, a]); // $ExpectType Observable<A[]>
});

it('should accept 1 param and a result selector', () => {
const o = combineLatest([a], (a: A) => new A()); // $ExpectType Observable<A>
});

it('should accept 2 params and a result selector', () => {
const o = combineLatest([a, b], (a: A, b: B) => new A()); // $ExpectType Observable<A>
});

it('should accept 3 params and a result selector', () => {
const o = combineLatest([a, b, c], (a: A, b: B, c: C) => new A()); // $ExpectType Observable<A>
});

it('should accept 4 params and a result selector', () => {
const o = combineLatest([a, b, c, d], (a: A, b: B, c: C, d: D) => new A()); // $ExpectType Observable<A>
});

it('should accept 5 params and a result selector', () => {
const o = combineLatest([a, b, c, d, e], (a: A, b: B, c: C, d: D, e: E) => new A()); // $ExpectType Observable<A>
});

it('should accept 6 params and a result selector', () => {
const o = combineLatest([a, b, c, d, e, f], (a: A, b: B, c: C, d: D, e: E, f: F) => new A()); // $ExpectType Observable<A>
});

it('should accept 7 or more params and a result selector', () => {
const o = combineLatest([a, b, c, d, e, f, g, g, g], (a: any, b: any, c: any, d: any, e: any, f: any, g1: any, g2: any, g3: any) => new A()); // $ExpectType Observable<A>
});
2 changes: 1 addition & 1 deletion spec-dtslint/observables/from-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ it('should accept an array of Inputs', () => {
yield 42;
}());

const o = from([of(1), ['test'], iterable]); // $ExpectType Observable<Observable<number> | IterableIterator<number> | string[]>
const o = from([of(1), ['test'], iterable]); // $ExpectType Observable<IterableIterator<number> | Observable<number> | string[]>
});
32 changes: 28 additions & 4 deletions src/internal/observable/combineLatest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@ import { fromArray } from './fromArray';
const NONE = {};

/* tslint:disable:max-line-length */

// If called with a single array, it "auto-spreads" the array, with result selector
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O1 extends ObservableInput<any>, R>(sources: [O1], resultSelector: (v1: ObservedValueOf<O1>) => R, scheduler?: SchedulerLike): Observable<R>;
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, R>(sources: [O1, O2], resultSelector: (v1: ObservedValueOf<O1>, v2: ObservedValueOf<O2>) => R, scheduler?: SchedulerLike): Observable<R>;
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, R>(sources: [O1, O2, O3], resultSelector: (v1: ObservedValueOf<O1>, v2: ObservedValueOf<O2>, v3: ObservedValueOf<O3>) => R, scheduler?: SchedulerLike): Observable<R>;
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>, R>(sources: [O1, O2, O3, O4], resultSelector: (v1: ObservedValueOf<O1>, v2: ObservedValueOf<O2>, v3: ObservedValueOf<O3>, v4: ObservedValueOf<O4>) => R, scheduler?: SchedulerLike): Observable<R>;
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>, O5 extends ObservableInput<any>, R>(sources: [O1, O2, O3, O4, O5], resultSelector: (v1: ObservedValueOf<O1>, v2: ObservedValueOf<O2>, v3: ObservedValueOf<O3>, v4: ObservedValueOf<O4>, v5: ObservedValueOf<O5>) => R, scheduler?: SchedulerLike): Observable<R>;
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>, O5 extends ObservableInput<any>, O6 extends ObservableInput<any>, R>(sources: [O1, O2, O3, O4, O5, O6], resultSelector: (v1: ObservedValueOf<O1>, v2: ObservedValueOf<O2>, v3: ObservedValueOf<O3>, v4: ObservedValueOf<O4>, v5: ObservedValueOf<O5>, v6: ObservedValueOf<O6>) => R, scheduler?: SchedulerLike): Observable<R>;
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O extends ObservableInput<any>, R>(sources: O[], resultSelector: (...args: ObservedValueOf<O>[]) => R, scheduler?: SchedulerLike): Observable<R>;

// standard call, but with a result selector
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O1 extends ObservableInput<any>, R>(v1: O1, resultSelector: (v1: ObservedValueOf<O1>) => R, scheduler?: SchedulerLike): Observable<R>;
/** @deprecated resultSelector no longer supported, pipe to map instead */
Expand All @@ -25,19 +43,25 @@ export function combineLatest<O1 extends ObservableInput<any>, O2 extends Observ
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>, O5 extends ObservableInput<any>, O6 extends ObservableInput<any>, R>(v1: O1, v2: O2, v3: O3, v4: O4, v5: O5, v6: O6, resultSelector: (v1: ObservedValueOf<O1>, v2: ObservedValueOf<O2>, v3: ObservedValueOf<O3>, v4: ObservedValueOf<O4>, v5: ObservedValueOf<O5>, v6: ObservedValueOf<O6>) => R, scheduler?: SchedulerLike): Observable<R>;

// If called with a single array, it "auto-spreads" the array.
export function combineLatest<O1 extends ObservableInput<any>>(sources: [O1], scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>>(sources: [O1, O2], scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>>(sources: [O1, O2, O3], scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>, ObservedValueOf<O3>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>>(sources: [O1, O2, O3, O4], scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>, ObservedValueOf<O3>, ObservedValueOf<O4>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>, O5 extends ObservableInput<any>>(sources: [O1, O2, O3, O4, O5], scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>, ObservedValueOf<O3>, ObservedValueOf<O4>, ObservedValueOf<O5>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>, O5 extends ObservableInput<any>, O6 extends ObservableInput<any>>(sources: [O1, O2, O3, O4, O5, O6], scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>, ObservedValueOf<O3>, ObservedValueOf<O4>, ObservedValueOf<O5>, ObservedValueOf<O6>]>;
export function combineLatest<O extends ObservableInput<any>>(sources: O[], scheduler?: SchedulerLike): Observable<ObservedValueOf<O>[]>;

// Standard calls
export function combineLatest<O1 extends ObservableInput<any>>(v1: O1, scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>>(v1: O1, v2: O2, scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>>(v1: O1, v2: O2, v3: O3, scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>, ObservedValueOf<O3>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>>(v1: O1, v2: O2, v3: O3, v4: O4, scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>, ObservedValueOf<O3>, ObservedValueOf<O4>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>, O5 extends ObservableInput<any>>(v1: O1, v2: O2, v3: O3, v4: O4, v5: O5, scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>, ObservedValueOf<O3>, ObservedValueOf<O4>, ObservedValueOf<O5>]>;
export function combineLatest<O1 extends ObservableInput<any>, O2 extends ObservableInput<any>, O3 extends ObservableInput<any>, O4 extends ObservableInput<any>, O5 extends ObservableInput<any>, O6 extends ObservableInput<any>>(v1: O1, v2: O2, v3: O3, v4: O4, v5: O5, v6: O6, scheduler?: SchedulerLike): Observable<[ObservedValueOf<O1>, ObservedValueOf<O2>, ObservedValueOf<O3>, ObservedValueOf<O4>, ObservedValueOf<O5>, ObservedValueOf<O6>]>;

export function combineLatest<O extends ObservableInput<any>>(array: O[], scheduler?: SchedulerLike): Observable<ObservedValueOf<O>[]>;
export function combineLatest<R>(array: ObservableInput<any>[], scheduler?: SchedulerLike): Observable<R>;
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<O extends ObservableInput<any>, R>(array: O[], resultSelector: (...values: ObservedValueOf<O>[]) => R, scheduler?: SchedulerLike): Observable<R>;
/** @deprecated resultSelector no longer supported, pipe to map instead */
export function combineLatest<R>(array: ObservableInput<any>[], resultSelector: (...values: Array<any>) => R, scheduler?: SchedulerLike): Observable<R>;
export function combineLatest<O extends ObservableInput<any>>(...observables: Array<O | SchedulerLike>): Observable<any[]>;
export function combineLatest<O extends ObservableInput<any>, R>(...observables: Array<O | ((...values: ObservedValueOf<O>[]) => R) | SchedulerLike>): Observable<R>;
export function combineLatest<R>(...observables: Array<ObservableInput<any> | ((...values: Array<any>) => R) | SchedulerLike>): Observable<R>;
Expand Down

0 comments on commit 40c3d9f

Please sign in to comment.