From e8adbb5d982c11b1c31d4e3a9a621df75748607a Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Mon, 26 Aug 2019 19:02:10 -0500 Subject: [PATCH] feat(of): Update of typings - `of()` now properly infers `Observable` - `of()` can handle any number of arguments gracefully BREAKING CHANGE: Generic signature changed, do not specify generics, allow them to be inferred or use `as` BREAKING CHANGE: Use with more than 9 arguments, where the last argument is a `SchedulerLike` may result in the wrong type which includes the `SchedulerLike`, even though the run time implementation does not support that. Developers should be using `scheduled` instead --- spec-dtslint/observables/of-spec.ts | 76 +++++++++++++++++++++++--- spec/observables/combineLatest-spec.ts | 4 +- src/internal/observable/concat.ts | 2 +- src/internal/observable/of.ts | 43 +++++++-------- src/internal/types.ts | 2 + 5 files changed, 93 insertions(+), 34 deletions(-) diff --git a/spec-dtslint/observables/of-spec.ts b/spec-dtslint/observables/of-spec.ts index c508c22505..f9b20d33c0 100644 --- a/spec-dtslint/observables/of-spec.ts +++ b/spec-dtslint/observables/of-spec.ts @@ -1,4 +1,4 @@ -import { of, animationFrameScheduler } from 'rxjs'; +import { of, animationFrameScheduler, queueScheduler } from 'rxjs'; import { A, B, C, D, E, F, G, H, I, J } from '../helpers'; const a = new A(); @@ -12,6 +12,16 @@ const h = new H(); const i = new I(); const j = new J(); +it('should infer never with 0 params', () => { + const res = of(); // $ExpectType Observable +}); + +it('forced generic should not cause an issue', () => { + const x: any = null; + const res = of(); // $ExpectType Observable + const res2 = of(x); // $ExpectType Observable +}); + it('should infer correctly with 1 param', () => { const res = of(new A()); // $ExpectType Observable }); @@ -52,13 +62,23 @@ it('should infer correcly with mono type of more than 9 params', () => { const res = of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // $ExpectType Observable }); -/* -TODO: The below test throws error where it should infer correctly with empty interface({}) -shoudl be able to comment back in when https://github.com/ReactiveX/rxjs/issues/4502 is resolved -it('should not support mixed type of more than 9 params', () => { - const res = of(a, b, c, d, e, f, g, h, i, j); // $TODO: Shoule ExpectType Observable<{}> +it('should support mixed type of 9 params', () => { + const res = of(a, b, c, d, e, f, g, h, i, j); // $ExpectType Observable +}); + +it('should support mixed type of 13 params', () => { + const res = of(a, b, c, d, e, f, g, h, i, j, '', true, 123, [1, 2, 3]); // $ExpectType Observable +}); + +it('should support a rest of params', () => { + const arr = [a, b, c, d, e, f, g, h, i, j]; + const res = of(...arr); // $ExpectType Observable + + const arr2 = ['test', 123, a]; + const res2 = of(...arr2); // $ExpectType Observable + + const res3 = of(b, ...arr2, c, true); // $ExpectType Observable }); - */ it('should support scheduler', () => { const res = of(a, animationFrameScheduler); // $ExpectType Observable @@ -67,3 +87,45 @@ it('should support scheduler', () => { it('should infer correctly with array', () => { const res = of([a, b, c]); // $ExpectType Observable<(A | B | C)[]> }); + + +// SchedulerLike inclusions (remove in v8) +it('should infer never with 0 params', () => { + const res = of(queueScheduler); // $ExpectType Observable +}); + +it('should infer correctly with 1 param', () => { + const res = of(new A(), queueScheduler); // $ExpectType Observable +}); + +it('should infer correcly with mixed type of 2 params', () => { + const res = of(a, b, queueScheduler); // $ExpectType Observable +}); + +it('should infer correcly with mixed type of 3 params', () => { + const res = of(a, b, c, queueScheduler); // $ExpectType Observable +}); + +it('should infer correcly with mixed type of 4 params', () => { + const res = of(a, b, c, d, queueScheduler); // $ExpectType Observable +}); + +it('should infer correcly with mixed type of 5 params', () => { + const res = of(a, b, c, d, e, queueScheduler); // $ExpectType Observable +}); + +it('should infer correcly with mixed type of 6 params', () => { + const res = of(a, b, c, d, e, f, queueScheduler); // $ExpectType Observable +}); + +it('should infer correcly with mixed type of 7 params', () => { + const res = of(a, b, c, d, e, f, g, queueScheduler); // $ExpectType Observable +}); + +it('should infer correcly with mixed type of 8 params', () => { + const res = of(a, b, c, d, e, f, g, h, queueScheduler); // $ExpectType Observable +}); + +it('should infer correcly with mixed type of 9 params', () => { + const res = of(a, b, c, d, e, f, g, h, i, queueScheduler); // $ExpectType Observable +}); \ No newline at end of file diff --git a/spec/observables/combineLatest-spec.ts b/spec/observables/combineLatest-spec.ts index d7e76bac1d..9603d1f593 100644 --- a/spec/observables/combineLatest-spec.ts +++ b/spec/observables/combineLatest-spec.ts @@ -21,8 +21,8 @@ describe('static combineLatest', () => { }); it('should combine an immediately-scheduled source with an immediately-scheduled second', (done) => { - const a = of(1, 2, 3, queueScheduler); - const b = of(4, 5, 6, 7, 8, queueScheduler); + const a = of(1, 2, 3, queueScheduler); + const b = of(4, 5, 6, 7, 8, queueScheduler); const r = [[1, 4], [2, 4], [2, 5], [3, 5], [3, 6], [3, 7], [3, 8]]; //type definition need to be updated diff --git a/src/internal/observable/concat.ts b/src/internal/observable/concat.ts index a75542c9ca..03bb07658f 100644 --- a/src/internal/observable/concat.ts +++ b/src/internal/observable/concat.ts @@ -139,5 +139,5 @@ export function concat(...observables: (ObservableInput | SchedulerLike) * @owner Observable */ export function concat, R>(...observables: Array): Observable | R> { - return concatAll()(of(...observables)); + return concatAll()(of(...observables) as Observable>); } diff --git a/src/internal/observable/of.ts b/src/internal/observable/of.ts index 67d5e1cc5d..10b1270a3b 100644 --- a/src/internal/observable/of.ts +++ b/src/internal/observable/of.ts @@ -1,47 +1,42 @@ -import { SchedulerLike } from '../types'; +import { SchedulerLike, ArrayValueOf } from '../types'; import { isScheduler } from '../util/isScheduler'; import { fromArray } from './fromArray'; import { Observable } from '../Observable'; import { scheduleArray } from '../scheduled/scheduleArray'; +import { never } from './never'; /* tslint:disable:max-line-length */ -/** @deprecated use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([], scheduler)` */ +export function of(scheduler: SchedulerLike): Observable; +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ export function of(a: T, scheduler: SchedulerLike): Observable; -/** @deprecated use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ export function of(a: T, b: T2, scheduler: SchedulerLike): Observable; -/** @deprecated use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ export function of(a: T, b: T2, c: T3, scheduler: SchedulerLike): Observable; -/** @deprecated use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ export function of(a: T, b: T2, c: T3, d: T4, scheduler: SchedulerLike): Observable; -/** @deprecated use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ export function of(a: T, b: T2, c: T3, d: T4, e: T5, scheduler: SchedulerLike): Observable; -/** @deprecated use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, scheduler: SchedulerLike): Observable; -/** @deprecated use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, scheduler: SchedulerLike): Observable; -/** @deprecated use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8, scheduler: SchedulerLike): Observable; -/** @deprecated use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ +/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */ export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8, i: T9, scheduler: SchedulerLike): Observable; -export function of(...args: (T | SchedulerLike)[]): Observable; // TODO(benlesh): Update the typings for this when we can switch to TS 3.x -export function of(a: T): Observable; -export function of(a: T, b: T2): Observable; -export function of(a: T, b: T2, c: T3): Observable; -export function of(a: T, b: T2, c: T3, d: T4): Observable; -export function of(a: T, b: T2, c: T3, d: T4, e: T5): Observable; -export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6): Observable; -export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7): - Observable; -export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8): - Observable; -export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8, i: T9): - Observable; -export function of(...args: T[]): Observable; +export function of(): Observable; +/** @deprecated remove in v8. Do not use generic arguments directly, allow inference or cast with `as` */ +export function of(): Observable; +/** @deprecated remove in v8. Do not use generic arguments directly, allow inference or cast with `as` */ +export function of(value: T): Observable; +export function of>(...args: A): Observable>; /* tslint:enable:max-line-length */ /** diff --git a/src/internal/types.ts b/src/internal/types.ts index e532dc809c..141cd691ca 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -101,3 +101,5 @@ export interface SchedulerAction extends Subscription { export type ObservedValueOf = O extends ObservableInput ? T : never; export type ObservedValuesFromArray = X extends Array> ? T : never; + +export type ArrayValueOf = A extends Array ? T : never; \ No newline at end of file