Skip to content

Commit

Permalink
docs(ObservableInput): add ObservableInput and SubscribableOrPromise …
Browse files Browse the repository at this point in the history
…descriptions

Add ObservableInput and SubscribableOrPromise interface descriptions,
as well as link these interfaces in type descriptions of operators,
so that users always know what kind of parameters they can pass to
used methods.
  • Loading branch information
mpodlasin committed Feb 14, 2017
1 parent 2889519 commit ede2fff
Show file tree
Hide file tree
Showing 18 changed files with 217 additions and 22 deletions.
195 changes: 195 additions & 0 deletions src/MiscJSDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,198 @@ export class ObserverDoc<T> {
return void 0;
}
}

/**
* `SubscribableOrPromise` interface describes all values that are observables,
* or can be treated as such. Every operator that accepts arguments annotated
* with this interface, can be also used with parameters that are not necessarily
* RxJS Observables.
*
* Following types of values might be passed to operators expecting this interface:
*
* ## Observable
*
* RxJS {@link Observable} instance.
*
* ## Observable-like (Subscribable)
*
* This might be any object that has `Symbol.observable` method. This method,
* when called, should return object with `subscribe` method on it, which should
* behave the same as RxJS `Observable.subscribe`.
*
* `Symbol.observable` is part of https://github.com/tc39/proposal-observable proposal.
* Since currently it is not supported natively, and every symbol is equal only to itself,
* you should use https://github.com/blesh/symbol-observable polyfill, when implementing
* custom Observable-likes.
*
* **TypeScript Subscribable interface issue**
*
* Although TypeScript interface claims that Subscribable is an object that has `subscribe`
* method declared directly on it, passing custom objects that have `subscribe`
* method but not `Symbol.observable` method will fail at runtime. Conversely, passing
* objects with `Symbol.observable` but without `subscribe` will fail at compile time
* (if you use TypeScript).
*
* TypeScript has problem supporting interfaces with methods defined as symbol
* properties. To get around that, you should implement `subscribe` directly on
* passed object, and make `Symbol.observable` method simply return `this`. That way
* everything will work as expected, and compiler will not complain. If you really
* do not want to put `subscribe` directly on your object, you will have to type cast
* it to `any`, before passing it to an operator.
*
* When TypeScript starts supporting interfaces with methods as symbol properties,
* Subscribable interface will only permit Observable-like objects with `Symbol.observable`
* defined, no matter if they themselves implement `subscribe` method or not.
*
* ## ES6 Promise
*
* Promise can be interpreted as Observable that emits value and completes
* when it is resolved or errors when it is rejected.
*
* ## Promise-like (Thenable)
*
* Promises passed to operators do not have to be native ES6 Promises.
* They can be implementations from popular Promise libraries, polyfills
* or even custom ones. They just need to have `then` method that works
* as the same as ES6 Promise `then`.
*
* @example <caption>Use merge and then map with non-RxJS observable</caption>
* const nonRxJSObservable = {
* subscribe(observer) {
* observer.next(1000);
* observer.complete();
* },
* [Symbol.observable]() {
* return this;
* }
* };
*
* Rx.Observable.merge(nonRxJSObservable)
* .map(value => "This value is " + value)
* .subscribe(result => console.log(result)); // Logs "This value is 1000"
*
*
* @example <caption>Use combineLatest with ES6 Promise</caption>
* Rx.Observable.combineLatest(Promise.resolve(5), Promise.resolve(10), Promise.resolve(15))
* .subscribe(
* value => console.log(value),
* err => {},
* () => console.log('the end!')
* );
* // Logs
* // [5, 10, 15]
* // "the end!"
*
*
* @interface
* @name SubscribableOrPromise
* @noimport true
*/
export class SubscribableOrPromiseDoc<T> {

}

/**
* `ObservableInput` interface describes all values that are observables,
* or can be treated as such. Every operator that accepts arguments annotated
* with this interface, can be also used with parameters that are not necessarily
* RxJS Observables.
*
* `ObservableInput` extends {@link SubscribableOrPromise}, which means you can use
* all types that fall under this interface, as well as:
*
* ## Array
*
* Arrays can be interpreted as observables that emit all values in array one by one,
* from left to right, and then complete immediately.
*
* ## Array-like
*
* Arrays passed to operators do not have to be built-in JavaScript Arrays. They
* can be also, for example, `arguments` property available inside every function,
* [DOM NodeList](https://developer.mozilla.org/pl/docs/Web/API/NodeList),
* or, actually, any object that has `length` property (which is a number)
* and stores values under non-negative (zero and up) integers.
*
* ## ES6 Iterable
*
* Operators will accept both built-in and custom ES6 Iterables, by treating them as
* observables that emit all its values in order of iteration and then complete
* when iteration ends. Note that contrary to arrays, Iterables do not have to
* necessarily be finite, so creating Observables that never complete is possible as well.
*
* Note that you can make iterator an instance of Iterable by having it return itself
* in `Symbol.iterator` method. It means that every operator accepting Iterables accepts,
* though indirectly, iterators themselves as well. All native ES6 iterators are instances
* of Iterable by default, so you do not have to implement their `Symbol.iterator` method
* yourself.
*
* **TypeScript Iterable interface issue**
*
* TypeScript `ObservableInput` interface actually lacks type signature for Iterables,
* because of issues it caused in some projects (see [this issue](https://github.com/ReactiveX/rxjs/issues/2306)).
* If you want to use Iterable as argument for operator, cast it to `any` first.
* Remember of course that, because of casting, you have to yourself ensure that passed
* argument really implements said interface.
*
* Observables that accept `ObservableInput` can actually accept any
*
* @example <caption>Use merge with arrays</caption>
* Rx.Observable.merge([1, 2], [4], [5, 6])
* .subscribe(
* value => console.log(value),
* err => {},
* () => console.log('ta dam!')
* );
*
* // Logs
* // 1
* // 2
* // 3
* // 4
* // 5
* // 6
* // "ta dam!"
*
*
* @example <caption>Use merge with array-like</caption>
* Rx.Observable.merge({0: 1, 1: 2, length: 2}, {0: 3, length: 1})
* .subscribe(
* value => console.log(value),
* err => {},
* () => console.log('nice, huh?')
* );
*
* // Logs
* // 1
* // 2
* // 3
* // "nice, huh?"
*
* @example <caption>Use merge with an Iterable (Map)</caption>
* const firstMap = new Map([[1, 'a'], [2, 'b']]);
* const secondMap = new Map([[3, 'c'], [4, 'd']]);
*
* Rx.Observable.merge(
* firstMap, // pass Iterable
* secondMap.values() // pass iterator, which is itself an Iterable
* ).subscribe(
* value => console.log(value),
* err => {},
* () => console.log('yup!')
* );
*
* // Logs
* // [1, "a"]
* // [2, "b"]
* // "c"
* // "d"
* // "yup!"
*
* @interface
* @name ObservableInput
* @noimport true
*/
export class ObservableInputDoc<T> {

}
2 changes: 1 addition & 1 deletion src/observable/DeferObservable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class DeferObservable<T> extends Observable<T> {
*
* @see {@link create}
*
* @param {function(): Observable|Promise} observableFactory The Observable
* @param {function(): SubscribableOrPromise} observableFactory The Observable
* factory function to invoke for each Observer that subscribes to the output
* Observable. May also return a Promise, which will be converted on the fly
* to an Observable.
Expand Down
4 changes: 2 additions & 2 deletions src/observable/FromObservable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ export class FromObservable<T> extends Observable<T> {
* @see {@link fromEventPattern}
* @see {@link fromPromise}
*
* @param {ObservableInput<T>} ish A subscribable object, a Promise, an
* @param {ObservableInput} ish A subscribable object, a Promise, an
* Observable-like, an Array, an iterable or an array-like object to be
* converted.
* @param {Scheduler} [scheduler] The scheduler on which to schedule the
* emissions of values.
* @return {Observable<T>} The Observable whose values are originally from the
* @return {Observable} The Observable whose values are originally from the
* input object that was converted.
* @static true
* @name from
Expand Down
4 changes: 2 additions & 2 deletions src/observable/combineLatest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ export function combineLatest<R>(...observables: Array<ObservableInput<any> | ((
* @see {@link merge}
* @see {@link withLatestFrom}
*
* @param {Observable} observable1 An input Observable to combine with the
* @param {ObservableInput} observable1 An input Observable to combine with the
* source Observable.
* @param {Observable} observable2 An input Observable to combine with the
* @param {ObservableInput} observable2 An input Observable to combine with the
* source Observable. More than one input Observables may be given as argument.
* @param {function} [project] An optional function to project the values from
* the combined latest values into a new value on the output Observable.
Expand Down
2 changes: 1 addition & 1 deletion src/operator/audit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { subscribeToResult } from '../util/subscribeToResult';
* @see {@link sample}
* @see {@link throttle}
*
* @param {function(value: T): Observable|Promise} durationSelector A function
* @param {function(value: T): SubscribableOrPromise} durationSelector A function
* that receives a value from the source Observable, for computing the silencing
* duration, returned as an Observable or a Promise.
* @return {Observable<T>} An Observable that performs rate-limiting of
Expand Down
2 changes: 1 addition & 1 deletion src/operator/combineLatest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function combineLatest<T, TOther, R>(this: Observable<T>, array: Observab
* @see {@link merge}
* @see {@link withLatestFrom}
*
* @param {Observable} other An input Observable to combine with the source
* @param {ObservableInput} other An input Observable to combine with the source
* Observable. More than one input Observables may be given as argument.
* @param {function} [project] An optional function to project the values from
* the combined latest values into a new value on the output Observable.
Expand Down
6 changes: 3 additions & 3 deletions src/operator/concat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function concat<T, R>(this: Observable<T>, ...observables: Array<Observab
* @see {@link concatMap}
* @see {@link concatMapTo}
*
* @param {Observable} other An input Observable to concatenate after the source
* @param {ObservableInput} other An input Observable to concatenate after the source
* Observable. More than one input Observables may be given as argument.
* @param {Scheduler} [scheduler=null] An optional IScheduler to schedule each
* Observable subscription on.
Expand Down Expand Up @@ -117,8 +117,8 @@ export function concatStatic<T, R>(...observables: (ObservableInput<any> | ISche
* @see {@link concatMap}
* @see {@link concatMapTo}
*
* @param {Observable} input1 An input Observable to concatenate with others.
* @param {Observable} input2 An input Observable to concatenate with others.
* @param {ObservableInput} input1 An input Observable to concatenate with others.
* @param {ObservableInput} input2 An input Observable to concatenate with others.
* More than one input Observables may be given as argument.
* @param {Scheduler} [scheduler=null] An optional IScheduler to schedule each
* Observable subscription on.
Expand Down
2 changes: 1 addition & 1 deletion src/operator/concatMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function concatMap<T, I, R>(this: Observable<T>, project: (value: T, inde
* @see {@link mergeMap}
* @see {@link switchMap}
*
* @param {function(value: T, ?index: number): Observable} project A function
* @param {function(value: T, ?index: number): ObservableInput} project A function
* that, when applied to an item emitted by the source Observable, returns an
* Observable.
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
Expand Down
2 changes: 1 addition & 1 deletion src/operator/concatMapTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function concatMapTo<T, I, R>(this: Observable<T>, observable: Observable
* @see {@link mergeMapTo}
* @see {@link switchMapTo}
*
* @param {Observable} innerObservable An Observable to replace each value from
* @param {ObservableInput} innerObservable An Observable to replace each value from
* the source Observable.
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
* A function to produce the value on the output Observable based on the values
Expand Down
2 changes: 1 addition & 1 deletion src/operator/debounce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { subscribeToResult } from '../util/subscribeToResult';
* @see {@link delayWhen}
* @see {@link throttle}
*
* @param {function(value: T): Observable|Promise} durationSelector A function
* @param {function(value: T): SubscribableOrPromise} durationSelector A function
* that receives a value from the source Observable, for computing the timeout
* duration for each source value, returned as an Observable or a Promise.
* @return {Observable} An Observable that delays the emissions of the source
Expand Down
2 changes: 1 addition & 1 deletion src/operator/exhaustMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function exhaustMap<T, I, R>(this: Observable<T>, project: (value: T, ind
* @see {@link mergeMap}
* @see {@link switchMap}
*
* @param {function(value: T, ?index: number): Observable} project A function
* @param {function(value: T, ?index: number): ObservableInput} project A function
* that, when applied to an item emitted by the source Observable, returns an
* Observable.
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
Expand Down
4 changes: 2 additions & 2 deletions src/operator/merge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function merge<T, R>(this: Observable<T>, ...observables: Array<Observabl
* @see {@link mergeMapTo}
* @see {@link mergeScan}
*
* @param {Observable} other An input Observable to merge with the source
* @param {ObservableInput} other An input Observable to merge with the source
* Observable. More than one input Observables may be given as argument.
* @param {number} [concurrent=Number.POSITIVE_INFINITY] Maximum number of input
* Observables being subscribed to concurrently.
Expand Down Expand Up @@ -136,7 +136,7 @@ export function mergeStatic<T, R>(...observables: (ObservableInput<any> | ISched
* @see {@link mergeMapTo}
* @see {@link mergeScan}
*
* @param {...Observable} observables Input Observables to merge together.
* @param {...ObservableInput} observables Input Observables to merge together.
* @param {number} [concurrent=Number.POSITIVE_INFINITY] Maximum number of input
* Observables being subscribed to concurrently.
* @param {Scheduler} [scheduler=null] The IScheduler to use for managing
Expand Down
2 changes: 1 addition & 1 deletion src/operator/mergeMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function mergeMap<T, I, R>(this: Observable<T>, project: (value: T, index
* @see {@link mergeScan}
* @see {@link switchMap}
*
* @param {function(value: T, ?index: number): Observable} project A function
* @param {function(value: T, ?index: number): ObservableInput} project A function
* that, when applied to an item emitted by the source Observable, returns an
* Observable.
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
Expand Down
2 changes: 1 addition & 1 deletion src/operator/mergeMapTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function mergeMapTo<T, I, R>(this: Observable<T>, observable: ObservableI
* @see {@link mergeScan}
* @see {@link switchMapTo}
*
* @param {Observable} innerObservable An Observable to replace each value from
* @param {ObservableInput} innerObservable An Observable to replace each value from
* the source Observable.
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
* A function to produce the value on the output Observable based on the values
Expand Down
2 changes: 1 addition & 1 deletion src/operator/switchMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function switchMap<T, I, R>(this: Observable<T>, project: (value: T, inde
* @see {@link switch}
* @see {@link switchMapTo}
*
* @param {function(value: T, ?index: number): Observable} project A function
* @param {function(value: T, ?index: number): ObservableInput} project A function
* that, when applied to an item emitted by the source Observable, returns an
* Observable.
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
Expand Down
2 changes: 1 addition & 1 deletion src/operator/switchMapTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function switchMapTo<T, I, R>(this: Observable<T>, observable: Observable
* @see {@link switchMap}
* @see {@link mergeMapTo}
*
* @param {Observable} innerObservable An Observable to replace each value from
* @param {ObservableInput} innerObservable An Observable to replace each value from
* the source Observable.
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
* A function to produce the value on the output Observable based on the values
Expand Down
2 changes: 1 addition & 1 deletion src/operator/throttle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { subscribeToResult } from '../util/subscribeToResult';
* @see {@link sample}
* @see {@link throttleTime}
*
* @param {function(value: T): Observable|Promise} durationSelector A function
* @param {function(value: T): SubscribableOrPromise} durationSelector A function
* that receives a value from the source Observable, for computing the silencing
* duration for each source value, returned as an Observable or a Promise.
* @return {Observable<T>} An Observable that performs the throttle operation to
Expand Down
2 changes: 1 addition & 1 deletion src/operator/withLatestFrom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function withLatestFrom<T, R>(this: Observable<T>, array: ObservableInput
*
* @see {@link combineLatest}
*
* @param {Observable} other An input Observable to combine with the source
* @param {ObservableInput} other An input Observable to combine with the source
* Observable. More than one input Observables may be given as argument.
* @param {Function} [project] Projection function for combining values
* together. Receives all values in order of the Observables passed, where the
Expand Down

0 comments on commit ede2fff

Please sign in to comment.