Skip to content

Commit

Permalink
feat(of): Update of typings
Browse files Browse the repository at this point in the history
- `of()` now properly infers `Observable<never>`
- `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
  • Loading branch information
benlesh committed Sep 3, 2019
1 parent 741a136 commit e8adbb5
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 34 deletions.
76 changes: 69 additions & 7 deletions spec-dtslint/observables/of-spec.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -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<never>
});

it('forced generic should not cause an issue', () => {
const x: any = null;
const res = of<string>(); // $ExpectType Observable<string>
const res2 = of<string>(x); // $ExpectType Observable<string>
});

it('should infer correctly with 1 param', () => {
const res = of(new A()); // $ExpectType Observable<A>
});
Expand Down Expand Up @@ -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<number>
});

/*
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<A | B | C | D | E | F | G | H | I | J>
});

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<string | number | boolean | number[] | A | B | C | D | E | F | G | H | I | J>
});

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<A | B | C | D | E | F | G | H | I | J>

const arr2 = ['test', 123, a];
const res2 = of(...arr2); // $ExpectType Observable<string | number | A>

const res3 = of(b, ...arr2, c, true); // $ExpectType Observable<string | number | boolean | A | B | C>
});
*/

it('should support scheduler', () => {
const res = of(a, animationFrameScheduler); // $ExpectType Observable<A>
Expand All @@ -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<never>
});

it('should infer correctly with 1 param', () => {
const res = of(new A(), queueScheduler); // $ExpectType Observable<A>
});

it('should infer correcly with mixed type of 2 params', () => {
const res = of(a, b, queueScheduler); // $ExpectType Observable<A | B>
});

it('should infer correcly with mixed type of 3 params', () => {
const res = of(a, b, c, queueScheduler); // $ExpectType Observable<A | B | C>
});

it('should infer correcly with mixed type of 4 params', () => {
const res = of(a, b, c, d, queueScheduler); // $ExpectType Observable<A | B | C | D>
});

it('should infer correcly with mixed type of 5 params', () => {
const res = of(a, b, c, d, e, queueScheduler); // $ExpectType Observable<A | B | C | D | E>
});

it('should infer correcly with mixed type of 6 params', () => {
const res = of(a, b, c, d, e, f, queueScheduler); // $ExpectType Observable<A | B | C | D | E | F>
});

it('should infer correcly with mixed type of 7 params', () => {
const res = of(a, b, c, d, e, f, g, queueScheduler); // $ExpectType Observable<A | B | C | D | E | F | G>
});

it('should infer correcly with mixed type of 8 params', () => {
const res = of(a, b, c, d, e, f, g, h, queueScheduler); // $ExpectType Observable<A | B | C | D | E | F | G | H>
});

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<A | B | C | D | E | F | G | H | I>
});
4 changes: 2 additions & 2 deletions spec/observables/combineLatest-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ describe('static combineLatest', () => {
});

it('should combine an immediately-scheduled source with an immediately-scheduled second', (done) => {
const a = of<number>(1, 2, 3, queueScheduler);
const b = of<number>(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
Expand Down
2 changes: 1 addition & 1 deletion src/internal/observable/concat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,5 @@ export function concat<R>(...observables: (ObservableInput<any> | SchedulerLike)
* @owner Observable
*/
export function concat<O extends ObservableInput<any>, R>(...observables: Array<O | SchedulerLike>): Observable<ObservedValueOf<O> | R> {
return concatAll<R>()(of(...observables));
return concatAll<R>()(of(...observables) as Observable<ObservedValueOf<O>>);
}
43 changes: 19 additions & 24 deletions src/internal/observable/of.ts
Original file line number Diff line number Diff line change
@@ -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<never>;
/** @deprecated remove in v8. Use {@link scheduled} instead `scheduled([a, b, c], scheduler)` */
export function of<T>(a: T, scheduler: SchedulerLike): Observable<T>;
/** @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<T, T2>(a: T, b: T2, scheduler: SchedulerLike): Observable<T | T2>;
/** @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<T, T2, T3>(a: T, b: T2, c: T3, scheduler: SchedulerLike): Observable<T | T2 | T3>;
/** @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<T, T2, T3, T4>(a: T, b: T2, c: T3, d: T4, scheduler: SchedulerLike): Observable<T | T2 | T3 | T4>;
/** @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<T, T2, T3, T4, T5>(a: T, b: T2, c: T3, d: T4, e: T5, scheduler: SchedulerLike): Observable<T | T2 | T3 | T4 | T5>;
/** @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<T, T2, T3, T4, T5, T6>(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, scheduler: SchedulerLike): Observable<T | T2 | T3 | T4 | T5 | T6>;
/** @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<T, T2, T3, T4, T5, T6, T7>(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, scheduler: SchedulerLike):
Observable<T | T2 | T3 | T4 | T5 | T6 | T7>;
/** @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<T, T2, T3, T4, T5, T6, T7, T8>(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8, scheduler: SchedulerLike):
Observable<T | T2 | T3 | T4 | T5 | T6 | T7 | T8>;
/** @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<T, T2, T3, T4, T5, T6, T7, T8, T9>(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8, i: T9, scheduler: SchedulerLike):
Observable<T | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9>;
export function of<T>(...args: (T | SchedulerLike)[]): Observable<T>;

// TODO(benlesh): Update the typings for this when we can switch to TS 3.x
export function of<T>(a: T): Observable<T>;
export function of<T, T2>(a: T, b: T2): Observable<T | T2>;
export function of<T, T2, T3>(a: T, b: T2, c: T3): Observable<T | T2 | T3>;
export function of<T, T2, T3, T4>(a: T, b: T2, c: T3, d: T4): Observable<T | T2 | T3 | T4>;
export function of<T, T2, T3, T4, T5>(a: T, b: T2, c: T3, d: T4, e: T5): Observable<T | T2 | T3 | T4 | T5>;
export function of<T, T2, T3, T4, T5, T6>(a: T, b: T2, c: T3, d: T4, e: T5, f: T6): Observable<T | T2 | T3 | T4 | T5 | T6>;
export function of<T, T2, T3, T4, T5, T6, T7>(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7):
Observable<T | T2 | T3 | T4 | T5 | T6 | T7>;
export function of<T, T2, T3, T4, T5, T6, T7, T8>(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8):
Observable<T | T2 | T3 | T4 | T5 | T6 | T7 | T8>;
export function of<T, T2, T3, T4, T5, T6, T7, T8, T9>(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8, i: T9):
Observable<T | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9>;
export function of<T>(...args: T[]): Observable<T>;
export function of(): Observable<never>;
/** @deprecated remove in v8. Do not use generic arguments directly, allow inference or cast with `as` */
export function of<T>(): Observable<T>;
/** @deprecated remove in v8. Do not use generic arguments directly, allow inference or cast with `as` */
export function of<T>(value: T): Observable<T>;
export function of<A extends Array<any>>(...args: A): Observable<ArrayValueOf<A>>;
/* tslint:enable:max-line-length */

/**
Expand Down
2 changes: 2 additions & 0 deletions src/internal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,5 @@ export interface SchedulerAction<T> extends Subscription {
export type ObservedValueOf<O> = O extends ObservableInput<infer T> ? T : never;

export type ObservedValuesFromArray<X> = X extends Array<ObservableInput<infer T>> ? T : never;

export type ArrayValueOf<A> = A extends Array<infer T> ? T : never;

0 comments on commit e8adbb5

Please sign in to comment.