Skip to content

Commit

Permalink
fix(types): support returning union types in exhaustMap
Browse files Browse the repository at this point in the history
  • Loading branch information
benlesh committed Jan 9, 2019
1 parent d8aa385 commit ff1f5dc
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 8 deletions.
11 changes: 11 additions & 0 deletions spec-dtslint/operators/exhaust-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,14 @@ it('should infer correctly', () => {
it('should enforce types', () => {
const o = of(1, 2, 3).pipe(exhaust()); // $ExpectError
});

// TODO(benlesh): The following test fails for TypeScript 3.1, but passes in TypeScript 3.2
// I'm unsure what we need to do to get this so it ignores the TS 3.1 failure, as that's a bug
// in TypeScript, and this is properly typed now.

// it('should support union types', () => {
// const a = Math.random() > 0.5 ? of(123) : of('abc');
// const b = Math.random() > 0.5 ? of(123) : of('abc');
// const source = of(a, b);
// const o = source.pipe(exhaust()); // $ExpectType Observable<string | number>
// });
4 changes: 4 additions & 0 deletions spec-dtslint/operators/exhaustMap-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ it('should support an undefined resultSelector', () => {
const o = of(1, 2, 3).pipe(exhaustMap(p => of(Boolean(p)), undefined)); // $ExpectType Observable<boolean>
});

it('should report projections to union types', () => {
const o = of(Math.random()).pipe(exhaustMap(n => n > 0.5 ? of('life') : of(42))); // $ExpectType Observable<string | number>
});

it('should enforce types', () => {
const o = of(1, 2, 3).pipe(exhaustMap()); // $ExpectError
});
Expand Down
16 changes: 8 additions & 8 deletions src/internal/operators/exhaustMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { Subscription } from '../Subscription';
import { OuterSubscriber } from '../OuterSubscriber';
import { InnerSubscriber } from '../InnerSubscriber';
import { subscribeToResult } from '../util/subscribeToResult';
import { ObservableInput, OperatorFunction } from '../types';
import { ObservableInput, OperatorFunction, ObservedValueOf } from '../types';
import { map } from './map';
import { from } from '../observable/from';

/* tslint:disable:max-line-length */
export function exhaustMap<T, R>(project: (value: T, index: number) => ObservableInput<R>): OperatorFunction<T, R>;
export function exhaustMap<T, O extends ObservableInput<any>>(project: (value: T, index: number) => O): OperatorFunction<T, ObservedValueOf<O>>;
/** @deprecated resultSelector is no longer supported. Use inner map instead. */
export function exhaustMap<T, R>(project: (value: T, index: number) => ObservableInput<R>, resultSelector: undefined): OperatorFunction<T, R>;
export function exhaustMap<T, O extends ObservableInput<any>>(project: (value: T, index: number) => O, resultSelector: undefined): OperatorFunction<T, ObservedValueOf<O>>;
/** @deprecated resultSelector is no longer supported. Use inner map instead. */
export function exhaustMap<T, I, R>(project: (value: T, index: number) => ObservableInput<I>, resultSelector: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R): OperatorFunction<T, R>;
/* tslint:enable:max-line-length */
Expand Down Expand Up @@ -59,15 +59,15 @@ export function exhaustMap<T, I, R>(project: (value: T, index: number) => Observ
* @method exhaustMap
* @owner Observable
*/
export function exhaustMap<T, I, R>(
project: (value: T, index: number) => ObservableInput<I>,
resultSelector?: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R,
): OperatorFunction<T, I|R> {
export function exhaustMap<T, R, O extends ObservableInput<any>>(
project: (value: T, index: number) => O,
resultSelector?: (outerValue: T, innerValue: ObservedValueOf<O>, outerIndex: number, innerIndex: number) => R,
): OperatorFunction<T, ObservedValueOf<O>|R> {
if (resultSelector) {
// DEPRECATED PATH
return (source: Observable<T>) => source.pipe(
exhaustMap((a, i) => from(project(a, i)).pipe(
map((b, ii) => resultSelector(a, b, i, ii)),
map((b: any, ii: any) => resultSelector(a, b, i, ii)),
)),
);
}
Expand Down

0 comments on commit ff1f5dc

Please sign in to comment.