From 81ee1f72408854f4017615fe7949edf5dd50533b Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Wed, 22 Jan 2020 17:36:13 -0600 Subject: [PATCH] fix(endWith): will properly type N arguments (#5246) * fix(endWith): will properly type N arguments * docs(endWith): minor improvements * docs(endWith): fix example imports --- spec-dtslint/operators/endWith-spec.ts | 50 +++++------------ src/internal/operators/endWith.ts | 75 +++++++++++++++----------- 2 files changed, 56 insertions(+), 69 deletions(-) diff --git a/spec-dtslint/operators/endWith-spec.ts b/spec-dtslint/operators/endWith-spec.ts index 8f4d3aaa2c..d4782ea5c5 100644 --- a/spec-dtslint/operators/endWith-spec.ts +++ b/spec-dtslint/operators/endWith-spec.ts @@ -1,42 +1,18 @@ import { of, asyncScheduler } from 'rxjs'; import { endWith } from 'rxjs/operators'; +import { a, b, c, d, e, f, g, h } from '../helpers'; it('should support a scheduler', () => { - const a = of(1, 2, 3).pipe(endWith(asyncScheduler)); // $ExpectType Observable -}); - -it('should infer type for 1 parameter', () => { - const a = of(1, 2, 3).pipe(endWith(4)); // $ExpectType Observable -}); - -it('should infer type for 2 parameter', () => { - const a = of(1, 2, 3).pipe(endWith(4, 5)); // $ExpectType Observable -}); - -it('should infer type for 3 parameter', () => { - const a = of(1, 2, 3).pipe(endWith(4, 5, 6)); // $ExpectType Observable -}); - -it('should infer type for 4 parameter', () => { - const a = of(1, 2, 3).pipe(endWith(4, 5, 6, 7)); // $ExpectType Observable -}); - -it('should infer type for 5 parameter', () => { - const a = of(1, 2, 3).pipe(endWith(4, 5, 6, 7, 8)); // $ExpectType Observable -}); - -it('should infer type for 6 parameter', () => { - const a = of(1, 2, 3).pipe(endWith(4, 5, 6, 7, 8, 9)); // $ExpectType Observable -}); - -it('should infer type for rest parameters', () => { - const a = of(1, 2, 3).pipe(endWith(4, 5, 6, 7, 8, 9, 10)); // $ExpectType Observable -}); - -it('should infer with different types', () => { - const a = of(1, 2, 3).pipe(endWith('4', true)); // $ExpectType Observable -}); - -it('should accept empty parameter', () => { - const a = of(1, 2, 3).pipe(endWith()); // $ExpectType Observable + const r = of(a).pipe(endWith(asyncScheduler)); // $ExpectType Observable +}); + +it('should infer type for N values', () => { + const r0 = of(a).pipe(endWith()); // $ExpectType Observable + const r1 = of(a).pipe(endWith(b)); // $ExpectType Observable + const r2 = of(a).pipe(endWith(b, c)); // $ExpectType Observable + const r3 = of(a).pipe(endWith(b, c, d)); // $ExpectType Observable + const r4 = of(a).pipe(endWith(b, c, d, e)); // $ExpectType Observable + const r5 = of(a).pipe(endWith(b, c, d, e, f)); // $ExpectType Observable + const r6 = of(a).pipe(endWith(b, c, d, e, f, g)); // $ExpectType Observable + const r7 = of(a).pipe(endWith(b, c, d, e, f, g, h)); // $ExpectType Observable }); diff --git a/src/internal/operators/endWith.ts b/src/internal/operators/endWith.ts index 46aa651e3f..1cbb0c0a94 100644 --- a/src/internal/operators/endWith.ts +++ b/src/internal/operators/endWith.ts @@ -1,7 +1,7 @@ import { Observable } from '../Observable'; import { concat } from '../observable/concat'; import { of } from '../observable/of'; -import { MonoTypeOperatorFunction, SchedulerLike, OperatorFunction } from '../types'; +import { MonoTypeOperatorFunction, SchedulerLike, OperatorFunction, ValueFromArray } from '../types'; /* tslint:disable:max-line-length */ /** @deprecated use {@link scheduled} and {@link concatAll} (e.g. `scheduled([source, [a, b, c]], scheduler).pipe(concatAll())`) */ @@ -19,49 +19,60 @@ export function endWith(v1: A, v2: B, v3: C, v4: D, v5: E, sch /** @deprecated use {@link scheduled} and {@link concatAll} (e.g. `scheduled([source, [a, b, c]], scheduler).pipe(concatAll())`) */ export function endWith(v1: A, v2: B, v3: C, v4: D, v5: E, v6: F, scheduler: SchedulerLike): OperatorFunction; -export function endWith(v1: A): OperatorFunction; -export function endWith(v1: A, v2: B): OperatorFunction; -export function endWith(v1: A, v2: B, v3: C): OperatorFunction; -export function endWith(v1: A, v2: B, v3: C, v4: D): OperatorFunction; -export function endWith(v1: A, v2: B, v3: C, v4: D, v5: E): OperatorFunction; -export function endWith(v1: A, v2: B, v3: C, v4: D, v5: E, v6: F): OperatorFunction; -export function endWith(...array: Z[]): OperatorFunction; -/** @deprecated use {@link scheduled} and {@link concatAll} (e.g. `scheduled([source, [a, b, c]], scheduler).pipe(concatAll())`) */ -export function endWith(...array: Array): OperatorFunction; +export function endWith(...args: A): OperatorFunction>; + /* tslint:enable:max-line-length */ /** - * Returns an Observable that emits the items you specify as arguments after it finishes emitting - * items emitted by the source Observable. + * Returns an observable that will emit all values from the source, then synchronously emit + * he provided value(s) immediately after the source completes. + * + * NOTE: Passing a last argument of a Scheduler is _deprecated_, and may result in incorrect + * types in TypeScript. + * + * This is useful for knowing when an observable ends. Particularly when paired with an + * operator like {@link takeUntil} * * ![](endWith.png) * * ## Example - * ### After the source observable completes, appends an emission and then completes too. + * + * Emit values to know when an interval starts and stops. The interval will + * stop when a user clicks anywhere on the document. * * ```ts - * import { of } from 'rxjs'; - * import { endWith } from 'rxjs/operators'; + * import { interval, fromEvent } from 'rxjs'; + * import { map, startWith, takeUntil, endWith } from 'rxjs/operators'; * - * of('hi', 'how are you?', 'sorry, I have to go now').pipe( - * endWith('goodbye!'), + * const ticker$ = interval(5000).pipe( + * map(() => 'tick'), + * ); + * + * const documentClicks$ = fromEvent(document, 'click'); + * + * ticker$.pipe( + * startWith('interval started'), + * takeUntil(documentClicks$), + * endWith('interval ended by click'), + * ) + * .subscribe( + * x = console.log(x); * ) - * .subscribe(word => console.log(word)); - * // result: - * // 'hi' - * // 'how are you?' - * // 'sorry, I have to go now' - * // 'goodbye!' + * + * // Result (assuming a user clicks after 15 seconds) + * // "interval started" + * // "tick" + * // "tick" + * // "tick" + * // "interval ended by click" * ``` * - * @param {...T} values - Items you want the modified Observable to emit last. - * @param {SchedulerLike} [scheduler] - A {@link SchedulerLike} to use for scheduling - * the emissions of the `next` notifications. - * @return {Observable} An Observable that emits the items emitted by the source Observable - * and then emits the items in the specified Iterable. - * @method endWith - * @owner Observable + * @param values - Items you want the modified Observable to emit last. + * + * @see startWith + * @see concat + * @see takeUntil */ -export function endWith(...array: Array): MonoTypeOperatorFunction { - return (source: Observable) => concat(source, of(...array)) as Observable; +export function endWith(...values: Array): MonoTypeOperatorFunction { + return (source: Observable) => concat(source, of(...values)) as Observable; }