diff --git a/src/index.ts b/src/index.ts index 6a154053a4..fb99fc134f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -185,7 +185,7 @@ export { take } from './internal/operators/take'; export { takeLast } from './internal/operators/takeLast'; export { takeUntil } from './internal/operators/takeUntil'; export { takeWhile } from './internal/operators/takeWhile'; -export { tap } from './internal/operators/tap'; +export { tap, TapObserver } from './internal/operators/tap'; export { throttle, ThrottleConfig } from './internal/operators/throttle'; export { throttleTime } from './internal/operators/throttleTime'; export { throwIfEmpty } from './internal/operators/throwIfEmpty'; diff --git a/src/internal/operators/tap.ts b/src/internal/operators/tap.ts index 6cc1d121fa..826d60b5a9 100644 --- a/src/internal/operators/tap.ts +++ b/src/internal/operators/tap.ts @@ -4,9 +4,71 @@ import { operate } from '../util/lift'; import { createOperatorSubscriber } from './OperatorSubscriber'; import { identity } from '../util/identity'; +/** + * An extension to the {@link Observer} interface used only by the {@link tap} operator. + * + * It provides a useful set of callbacks a user can register to do side-effects in + * cases other than what the usual {@link Observer} callbacks are + * ({@link guide/glossary-and-semantics#next next}, + * {@link guide/glossary-and-semantics#error error} and/or + * {@link guide/glossary-and-semantics#complete complete}). + * + * ## Example + * + * ```ts + * import { fromEvent, switchMap, tap, interval, take } from 'rxjs'; + * + * const source$ = fromEvent(document, 'click'); + * const result$ = source$.pipe( + * switchMap((_, i) => i % 2 === 0 + * ? fromEvent(document, 'mousemove').pipe( + * tap({ + * subscribe: () => console.log('Subscribed to the mouse move events after click #' + i), + * unsubscribe: () => console.log('Mouse move events #' + i + ' unsubscribed'), + * finalize: () => console.log('Mouse move events #' + i + ' finalized') + * }) + * ) + * : interval(1_000).pipe( + * take(5), + * tap({ + * subscribe: () => console.log('Subscribed to the 1-second interval events after click #' + i), + * unsubscribe: () => console.log('1-second interval events #' + i + ' unsubscribed'), + * finalize: () => console.log('1-second interval events #' + i + ' finalized') + * }) + * ) + * ) + * ); + * + * const subscription = result$.subscribe({ + * next: console.log + * }); + * + * setTimeout(() => { + * console.log('Unsubscribe after 60 seconds'); + * subscription.unsubscribe(); + * }, 60_000); + * ``` + */ export interface TapObserver extends Observer { + /** + * The callback that `tap` operator invokes at the moment when the source Observable + * gets subscribed to. + */ subscribe: () => void; + /** + * The callback that `tap` operator invokes when an explicit + * {@link guide/glossary-and-semantics#unsubscription unsubscribe} happens. It won't get invoked on + * `error` or `complete` events. + */ unsubscribe: () => void; + /** + * The callback that `tap` operator invokes when any kind of + * {@link guide/glossary-and-semantics#finalization finalization} happens - either when + * the source Observable `error`s or `complete`s or when it gets explicitly unsubscribed + * by the user. There is no difference in using this callback or the {@link finalize} + * operator, but if you're already using `tap` operator, you can use this callback + * instead. You'd get the same result in either case. + */ finalize: () => void; } @@ -87,11 +149,9 @@ export interface TapObserver extends Observer { * ``` * * @see {@link finalize} - * @see {@link Observable#subscribe} + * @see {@link TapObserver} * * @param observerOrNext A next handler or partial observer - * @param error An error handler - * @param complete A completion handler * @return A function that returns an Observable identical to the source, but * runs the specified Observer or callback(s) for each item. */ diff --git a/src/operators/index.ts b/src/operators/index.ts index 61fcd831c9..895b2ccde0 100644 --- a/src/operators/index.ts +++ b/src/operators/index.ts @@ -92,7 +92,7 @@ export { take } from '../internal/operators/take'; export { takeLast } from '../internal/operators/takeLast'; export { takeUntil } from '../internal/operators/takeUntil'; export { takeWhile } from '../internal/operators/takeWhile'; -export { tap } from '../internal/operators/tap'; +export { tap, TapObserver } from '../internal/operators/tap'; export { throttle, ThrottleConfig } from '../internal/operators/throttle'; export { throttleTime } from '../internal/operators/throttleTime'; export { throwIfEmpty } from '../internal/operators/throwIfEmpty';