Skip to content

Commit 42589d0

Browse files
committed
feat(exhaustMap): simplify interface
- Removes resultSelector argument - updates tests BREAKING CHANGE: `resultSelector` no longer supported, to get this functionality use: `source.pipe(exhaustMap(x => of(x + x).pipe(map(y => x + y))))`
1 parent 959fb6a commit 42589d0

File tree

3 files changed

+20
-117
lines changed

3 files changed

+20
-117
lines changed

spec/operators/exhaustMap-spec.ts

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -75,23 +75,6 @@ describe('Observable.prototype.exhaustMap', () => {
7575
expectSubscriptions(e1.subscriptions).toBe(e1subs);
7676
});
7777

78-
it('should raise error if selector throws', () => {
79-
const x = cold( '--a--b--c--| ');
80-
const xsubs = ' ^ ! ';
81-
const e1 = hot('---x---------y----z----|');
82-
const e1subs = '^ ! ';
83-
const expected = '-----# ';
84-
85-
const result = e1.exhaustMap((value) => x,
86-
() => {
87-
throw 'error';
88-
});
89-
90-
expectObservable(result).toBe(expected);
91-
expectSubscriptions(x.subscriptions).toBe(xsubs);
92-
expectSubscriptions(e1.subscriptions).toBe(e1subs);
93-
});
94-
9578
it('should switch with a selector function', () => {
9679
const x = cold( '--a--b--c--| ');
9780
const xsubs = ' ^ ! ';
@@ -336,39 +319,4 @@ describe('Observable.prototype.exhaustMap', () => {
336319
expectSubscriptions(x.subscriptions).toBe(xsubs);
337320
expectSubscriptions(e1.subscriptions).toBe(e1subs);
338321
});
339-
340-
it('should switch with resultSelector goodness', () => {
341-
const x = cold( '--a--b--c--d--e-| ');
342-
const xsubs = ' ^ ! ';
343-
const y = cold( '---f---g---h---i--| ');
344-
const ysubs: string[] = [];
345-
const z = cold( '---k---l---m---n--|');
346-
const zsubs = ' ^ !';
347-
const e1 = hot('--x---------y------z-| ');
348-
const e1subs = '^ !';
349-
const expected = '----a--b--c--d--e-----k---l---m---n--|';
350-
351-
const observableLookup = { x: x, y: y, z: z };
352-
353-
const expectedValues = {
354-
a: ['x', 'a', 0, 0],
355-
b: ['x', 'b', 0, 1],
356-
c: ['x', 'c', 0, 2],
357-
d: ['x', 'd', 0, 3],
358-
e: ['x', 'e', 0, 4],
359-
k: ['z', 'k', 1, 0],
360-
l: ['z', 'l', 1, 1],
361-
m: ['z', 'm', 1, 2],
362-
n: ['z', 'n', 1, 3],
363-
};
364-
365-
const result = e1.exhaustMap((value) => observableLookup[value],
366-
(innerValue, outerValue, innerIndex, outerIndex) => [innerValue, outerValue, innerIndex, outerIndex]);
367-
368-
expectObservable(result).toBe(expected, expectedValues);
369-
expectSubscriptions(x.subscriptions).toBe(xsubs);
370-
expectSubscriptions(y.subscriptions).toBe(ysubs);
371-
expectSubscriptions(z.subscriptions).toBe(zsubs);
372-
expectSubscriptions(e1.subscriptions).toBe(e1subs);
373-
});
374322
});

src/internal/operators/exhaustMap.ts

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ import { InnerSubscriber } from '../InnerSubscriber';
77
import { subscribeToResult } from '../util/subscribeToResult';
88
import { ObservableInput, OperatorFunction } from '../types';
99

10-
/* tslint:disable:max-line-length */
11-
export function exhaustMap<T, R>(project: (value: T, index: number) => ObservableInput<R>): OperatorFunction<T, R>;
12-
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>;
13-
/* tslint:enable:max-line-length */
14-
1510
/**
1611
* Projects each source value to an Observable which is merged in the output
1712
* Observable only if the previous projected Observable has completed.
@@ -43,34 +38,23 @@ export function exhaustMap<T, I, R>(project: (value: T, index: number) => Observ
4338
* @param {function(value: T, ?index: number): ObservableInput} project A function
4439
* that, when applied to an item emitted by the source Observable, returns an
4540
* Observable.
46-
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
47-
* A function to produce the value on the output Observable based on the values
48-
* and the indices of the source (outer) emission and the inner Observable
49-
* emission. The arguments passed to this function are:
50-
* - `outerValue`: the value that came from the source
51-
* - `innerValue`: the value that came from the projected Observable
52-
* - `outerIndex`: the "index" of the value that came from the source
53-
* - `innerIndex`: the "index" of the value from the projected Observable
5441
* @return {Observable} An Observable containing projected Observables
5542
* of each item of the source, ignoring projected Observables that start before
5643
* their preceding Observable has completed.
5744
* @method exhaustMap
5845
* @owner Observable
5946
*/
60-
export function exhaustMap<T, I, R>(
61-
project: (value: T, index: number) => ObservableInput<I>,
62-
resultSelector?: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R
63-
): OperatorFunction<T, R> {
64-
return (source: Observable<T>) => source.lift(new SwitchFirstMapOperator(project, resultSelector));
65-
}
47+
export function exhaustMap<T, R>(project: (value: T, index: number) => ObservableInput<R>): OperatorFunction<T, R> {
48+
return (source: Observable<T>) =>
49+
source.lift(new SwitchFirstMapOperator(project));
50+
}
6651

67-
class SwitchFirstMapOperator<T, I, R> implements Operator<T, R> {
68-
constructor(private project: (value: T, index: number) => ObservableInput<I>,
69-
private resultSelector?: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R) {
52+
class SwitchFirstMapOperator<T, R> implements Operator<T, R> {
53+
constructor(private project: (value: T, index: number) => ObservableInput<R>) {
7054
}
7155

7256
call(subscriber: Subscriber<R>, source: any): any {
73-
return source.subscribe(new SwitchFirstMapSubscriber(subscriber, this.project, this.resultSelector));
57+
return source.subscribe(new SwitchFirstMapSubscriber(subscriber, this.project));
7458
}
7559
}
7660

@@ -79,14 +63,13 @@ class SwitchFirstMapOperator<T, I, R> implements Operator<T, R> {
7963
* @ignore
8064
* @extends {Ignored}
8165
*/
82-
class SwitchFirstMapSubscriber<T, I, R> extends OuterSubscriber<T, I> {
83-
private hasSubscription: boolean = false;
84-
private hasCompleted: boolean = false;
85-
private index: number = 0;
66+
class SwitchFirstMapSubscriber<T, R> extends OuterSubscriber<T, R> {
67+
private hasSubscription = false;
68+
private hasCompleted = false;
69+
private index = 0;
8670

8771
constructor(destination: Subscriber<R>,
88-
private project: (value: T, index: number) => ObservableInput<I>,
89-
private resultSelector?: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R) {
72+
private project: (value: T, index: number) => ObservableInput<R>) {
9073
super(destination);
9174
}
9275

@@ -115,26 +98,10 @@ class SwitchFirstMapSubscriber<T, I, R> extends OuterSubscriber<T, I> {
11598
}
11699
}
117100

118-
notifyNext(outerValue: T, innerValue: I,
101+
notifyNext(outerValue: T, innerValue: R,
119102
outerIndex: number, innerIndex: number,
120-
innerSub: InnerSubscriber<T, I>): void {
121-
const { resultSelector, destination } = this;
122-
if (resultSelector) {
123-
this.trySelectResult(outerValue, innerValue, outerIndex, innerIndex);
124-
} else {
125-
destination.next(innerValue);
126-
}
127-
}
128-
129-
private trySelectResult(outerValue: T, innerValue: I,
130-
outerIndex: number, innerIndex: number): void {
131-
const { resultSelector, destination } = this;
132-
try {
133-
const result = resultSelector(outerValue, innerValue, outerIndex, innerIndex);
134-
destination.next(result);
135-
} catch (err) {
136-
destination.error(err);
137-
}
103+
innerSub: InnerSubscriber<T, R>): void {
104+
this.destination.next(innerValue);
138105
}
139106

140107
notifyError(err: any): void {

src/internal/patching/operator/exhaustMap.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22
import { Observable } from '../../Observable';
33
import { ObservableInput } from '../../types';
44
import { exhaustMap as higherOrder } from '../../operators/exhaustMap';
5-
6-
/* tslint:disable:max-line-length */
7-
export function exhaustMap<T, R>(this: Observable<T>, project: (value: T, index: number) => ObservableInput<R>): Observable<R>;
8-
export function exhaustMap<T, I, R>(this: Observable<T>, project: (value: T, index: number) => ObservableInput<I>, resultSelector: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R): Observable<R>;
9-
/* tslint:enable:max-line-length */
10-
115
/**
126
* Projects each source value to an Observable which is merged in the output
137
* Observable only if the previous projected Observable has completed.
@@ -39,21 +33,15 @@ export function exhaustMap<T, I, R>(this: Observable<T>, project: (value: T, ind
3933
* @param {function(value: T, ?index: number): ObservableInput} project A function
4034
* that, when applied to an item emitted by the source Observable, returns an
4135
* Observable.
42-
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
43-
* A function to produce the value on the output Observable based on the values
44-
* and the indices of the source (outer) emission and the inner Observable
45-
* emission. The arguments passed to this function are:
46-
* - `outerValue`: the value that came from the source
47-
* - `innerValue`: the value that came from the projected Observable
48-
* - `outerIndex`: the "index" of the value that came from the source
49-
* - `innerIndex`: the "index" of the value from the projected Observable
5036
* @return {Observable} An Observable containing projected Observables
5137
* of each item of the source, ignoring projected Observables that start before
5238
* their preceding Observable has completed.
5339
* @method exhaustMap
5440
* @owner Observable
5541
*/
56-
export function exhaustMap<T, I, R>(this: Observable<T>, project: (value: T, index: number) => ObservableInput<I>,
57-
resultSelector?: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R): Observable<R> {
58-
return higherOrder(project, resultSelector)(this);
42+
export function exhaustMap<T, R>(
43+
this: Observable<T>,
44+
project: (value: T, index: number) => ObservableInput<R>
45+
): Observable<R> {
46+
return higherOrder(project)(this);
5947
}

0 commit comments

Comments
 (0)