Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(startWith): accepts N arguments and returns correct type #5247

Merged
merged 2 commits into from
Apr 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions spec-dtslint/operators/startWith-spec.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,24 @@
import { of, asyncScheduler } from 'rxjs';
import { startWith } from 'rxjs/operators';
import { a, b, c, d, e, f, g, h } from '../helpers';

it('should infer correctly with one value', () => {
const o = of(1, 2, 3).pipe(startWith(4)); // $ExpectType Observable<number>
});

it('should infer correctly with multiple values', () => {
const o = of(1, 2, 3).pipe(startWith(4, 5, 6)); // $ExpectType Observable<number>
});

it('should infer correctly with no value', () => {
const o = of(1, 2, 3).pipe(startWith()); // $ExpectType Observable<number>
});

it('should infer correctly with a value and a scheduler', () => {
const o = of(1, 2, 3).pipe(startWith(5, asyncScheduler)); // $ExpectType Observable<number>
});

it('should infer correctly with a different type', () => {
const o = of(1, 2, 3).pipe(startWith('foo')); // $ExpectType Observable<string | number>
});

it('should infer correctly with multiple different types', () => {
const o = of(1, 2, 3).pipe(startWith('foo', 4, true)); // $ExpectType Observable<string | number | boolean>
it('should infer correctly with N values', () => {
const r0 = of(a).pipe(startWith()); // $ExpectType Observable<A>
const r1 = of(a).pipe(startWith(b)); // $ExpectType Observable<A | B>
const r2 = of(a).pipe(startWith(b, c)); // $ExpectType Observable<A | B | C>
const r3 = of(a).pipe(startWith(b, c, d)); // $ExpectType Observable<A | B | C | D>
const r4 = of(a).pipe(startWith(b, c, d, e)); // $ExpectType Observable<A | B | C | D | E>
const r5 = of(a).pipe(startWith(b, c, d, e, f)); // $ExpectType Observable<A | B | C | D | E | F>
const r6 = of(a).pipe(startWith(b, c, d, e, f, g)); // $ExpectType Observable<A | B | C | D | E | F | G>
const r7 = of(a).pipe(startWith(b, c, d, e, f, g, h)); // $ExpectType Observable<A | B | C | D | E | F | G | H>
});

it('should infer correctly with only a scheduler', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit: test description is now out-of-date

const o = of(1, 2, 3).pipe(startWith(asyncScheduler)); // $ExpectType Observable<number>
});
const r = of(a).pipe(startWith(asyncScheduler)); // $ExpectType Observable<A>
const r1 = of(a).pipe(startWith(b, asyncScheduler)); // $ExpectType Observable<A | B>
const r2 = of(a).pipe(startWith(b, c, asyncScheduler)); // $ExpectType Observable<A | B | C>
const r3 = of(a).pipe(startWith(b, c, d, asyncScheduler)); // $ExpectType Observable<A | B | C | D>
const r4 = of(a).pipe(startWith(b, c, d, e, asyncScheduler)); // $ExpectType Observable<A | B | C | D | E>
const r5 = of(a).pipe(startWith(b, c, d, e, f, asyncScheduler)); // $ExpectType Observable<A | B | C | D | E | F>
const r6 = of(a).pipe(startWith(b, c, d, e, f, g, asyncScheduler)); // $ExpectType Observable<A | B | C | D | E | F | G>
});
59 changes: 27 additions & 32 deletions src/internal/operators/startWith.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Observable } from '../Observable';
import { concat } from '../observable/concat';
import { isScheduler } from '../util/isScheduler';
import { MonoTypeOperatorFunction, OperatorFunction, SchedulerLike } from '../types';
import { MonoTypeOperatorFunction, OperatorFunction, SchedulerLike, ValueFromArray } from '../types';

/* tslint:disable:max-line-length */
/** @deprecated use {@link scheduled} and {@link concatAll} (e.g. `scheduled([[a, b, c], source], scheduler).pipe(concatAll())`) */
Expand All @@ -19,20 +19,14 @@ export function startWith<T, D, E, F, G, H>(v1: D, v2: E, v3: F, v4: G, v5: H, s
/** @deprecated use {@link scheduled} and {@link concatAll} (e.g. `scheduled([[a, b, c], source], scheduler).pipe(concatAll())`) */
export function startWith<T, D, E, F, G, H, I>(v1: D, v2: E, v3: F, v4: G, v5: H, v6: I, scheduler: SchedulerLike): OperatorFunction<T, T | D | E | F | G | H | I>;

export function startWith<T, D>(v1: D): OperatorFunction<T, T | D>;
export function startWith<T, D, E>(v1: D, v2: E): OperatorFunction<T, T | D | E>;
export function startWith<T, D, E, F>(v1: D, v2: E, v3: F): OperatorFunction<T, T | D | E | F>;
export function startWith<T, D, E, F, G>(v1: D, v2: E, v3: F, v4: G): OperatorFunction<T, T | D | E | F | G>;
export function startWith<T, D, E, F, G, H>(v1: D, v2: E, v3: F, v4: G, v5: H): OperatorFunction<T, T | D | E | F | G | H>;
export function startWith<T, D, E, F, G, H, I>(v1: D, v2: E, v3: F, v4: G, v5: H, v6: I): OperatorFunction<T, T | D | E | F | G | H | I>;
export function startWith<T, D = T>(...array: D[]): OperatorFunction<T, T | D>;
/** @deprecated use {@link scheduled} and {@link concatAll} (e.g. `scheduled([[a, b, c], source], scheduler).pipe(concatAll())`) */
export function startWith<T, D = T>(...array: Array<D | SchedulerLike>): OperatorFunction<T, T | D>;
/* tslint:enable:max-line-length */
export function startWith<T, A extends any[]>(...values: A): OperatorFunction<T, T | ValueFromArray<A>>;

/**
* Returns an Observable that emits the items you specify as arguments before it begins to emit
* items emitted by the source Observable.
* Returns an observable that, at the moment of subscription, will synchronously emit all
* values provided to this operator, then subscribe to the source and mirror all of its emissions
* to subscribers.
*
* This is a useful way to know when subscription has occurred on an existing observable.
*
* <span class="informal">First emits its arguments in order, and then any
* emissions from the source.</span>
Expand All @@ -41,36 +35,37 @@ export function startWith<T, D = T>(...array: Array<D | SchedulerLike>): Operato
*
* ## Examples
*
* Start the chain of emissions with `"first"`, `"second"`
* Emit a value when a timer starts.
*
* ```ts
* import { of } from 'rxjs';
* import { startWith } from 'rxjs/operators';
* import { timer } from 'rxjs';
* import { startWith, map } from 'rxjs/operators';
*
* of("from source")
* .pipe(startWith("first", "second"))
* timer(1000)
* .pipe(
* map(() => 'timer emit'),
* startWith('timer start')
* )
* .subscribe(x => console.log(x));
*
* // results:
* // "first"
* // "second"
* // "from source"
* // "timer start"
* // "timer emit"
* ```
*
* @param {...T} values - Items you want the modified Observable to emit first.
* @param {SchedulerLike} [scheduler] - A {@link SchedulerLike} to use for scheduling
* the emissions of the `next` notifications.
* @return {Observable} An Observable that emits the items in the specified Iterable and then emits the items
* emitted by the source Observable.
* @name startWith
* @param values Items you want the modified Observable to emit first.
*
* @see endWith
* @see finalize
* @see concat
*/
export function startWith<T, D>(...array: Array<D | SchedulerLike>): OperatorFunction<T, T | D> {
const scheduler = array[array.length - 1] as SchedulerLike;
export function startWith<T, D>(...values: D[]): OperatorFunction<T, T | D> {
const scheduler = values[values.length - 1];
if (isScheduler(scheduler)) {
// deprecated path
array.pop();
return (source: Observable<T>) => concat(array as D[], source, scheduler);
values.pop();
return (source: Observable<T>) => concat(values, source, scheduler);
} else {
return (source: Observable<T>) => concat(array as D[], source);
return (source: Observable<T>) => concat(values, source);
}
}