Skip to content

Commit

Permalink
fix(endWith): will properly type N arguments (#5246)
Browse files Browse the repository at this point in the history
* fix(endWith): will properly type N arguments

* docs(endWith): minor improvements

* docs(endWith): fix example imports
  • Loading branch information
benlesh committed Jan 22, 2020
1 parent fa13149 commit 81ee1f7
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 69 deletions.
50 changes: 13 additions & 37 deletions 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<number>
});

it('should infer type for 1 parameter', () => {
const a = of(1, 2, 3).pipe(endWith(4)); // $ExpectType Observable<number>
});

it('should infer type for 2 parameter', () => {
const a = of(1, 2, 3).pipe(endWith(4, 5)); // $ExpectType Observable<number>
});

it('should infer type for 3 parameter', () => {
const a = of(1, 2, 3).pipe(endWith(4, 5, 6)); // $ExpectType Observable<number>
});

it('should infer type for 4 parameter', () => {
const a = of(1, 2, 3).pipe(endWith(4, 5, 6, 7)); // $ExpectType Observable<number>
});

it('should infer type for 5 parameter', () => {
const a = of(1, 2, 3).pipe(endWith(4, 5, 6, 7, 8)); // $ExpectType Observable<number>
});

it('should infer type for 6 parameter', () => {
const a = of(1, 2, 3).pipe(endWith(4, 5, 6, 7, 8, 9)); // $ExpectType Observable<number>
});

it('should infer type for rest parameters', () => {
const a = of(1, 2, 3).pipe(endWith(4, 5, 6, 7, 8, 9, 10)); // $ExpectType Observable<number>
});

it('should infer with different types', () => {
const a = of(1, 2, 3).pipe(endWith('4', true)); // $ExpectType Observable<string | number | boolean>
});

it('should accept empty parameter', () => {
const a = of(1, 2, 3).pipe(endWith()); // $ExpectType Observable<number>
const r = of(a).pipe(endWith(asyncScheduler)); // $ExpectType Observable<A>
});

it('should infer type for N values', () => {
const r0 = of(a).pipe(endWith()); // $ExpectType Observable<A>
const r1 = of(a).pipe(endWith(b)); // $ExpectType Observable<A | B>
const r2 = of(a).pipe(endWith(b, c)); // $ExpectType Observable<A | B | C>
const r3 = of(a).pipe(endWith(b, c, d)); // $ExpectType Observable<A | B | C | D>
const r4 = of(a).pipe(endWith(b, c, d, e)); // $ExpectType Observable<A | B | C | D | E>
const r5 = of(a).pipe(endWith(b, c, d, e, f)); // $ExpectType Observable<A | B | C | D | E | F>
const r6 = of(a).pipe(endWith(b, c, d, e, f, g)); // $ExpectType Observable<A | B | C | D | E | F | G>
const r7 = of(a).pipe(endWith(b, c, d, e, f, g, h)); // $ExpectType Observable<A | B | C | D | E | F | G | H>
});
75 changes: 43 additions & 32 deletions 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())`) */
Expand All @@ -19,49 +19,60 @@ export function endWith<T, A, B, C, D, E>(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<T, A, B, C, D, E, F>(v1: A, v2: B, v3: C, v4: D, v5: E, v6: F, scheduler: SchedulerLike): OperatorFunction<T, T | A | B | C | D | E | F>;

export function endWith<T, A>(v1: A): OperatorFunction<T, T | A>;
export function endWith<T, A, B>(v1: A, v2: B): OperatorFunction<T, T | A | B>;
export function endWith<T, A, B, C>(v1: A, v2: B, v3: C): OperatorFunction<T, T | A | B | C>;
export function endWith<T, A, B, C, D>(v1: A, v2: B, v3: C, v4: D): OperatorFunction<T, T | A | B | C | D>;
export function endWith<T, A, B, C, D, E>(v1: A, v2: B, v3: C, v4: D, v5: E): OperatorFunction<T, T | A | B | C | D | E>;
export function endWith<T, A, B, C, D, E, F>(v1: A, v2: B, v3: C, v4: D, v5: E, v6: F): OperatorFunction<T, T | A | B | C | D | E | F>;
export function endWith<T, Z = T>(...array: Z[]): OperatorFunction<T, T | Z>;
/** @deprecated use {@link scheduled} and {@link concatAll} (e.g. `scheduled([source, [a, b, c]], scheduler).pipe(concatAll())`) */
export function endWith<T, Z = T>(...array: Array<Z | SchedulerLike>): OperatorFunction<T, T | Z>;
export function endWith<T, A extends any[]>(...args: A): OperatorFunction<T, T | ValueFromArray<A>>;

/* 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<T>(...array: Array<T | SchedulerLike>): MonoTypeOperatorFunction<T> {
return (source: Observable<T>) => concat(source, of(...array)) as Observable<T>;
export function endWith<T>(...values: Array<T | SchedulerLike>): MonoTypeOperatorFunction<T> {
return (source: Observable<T>) => concat(source, of(...values)) as Observable<T>;
}

0 comments on commit 81ee1f7

Please sign in to comment.