diff --git a/src/MiscJSDoc.ts b/src/MiscJSDoc.ts index d9ca775a610..c7fcd50291b 100644 --- a/src/MiscJSDoc.ts +++ b/src/MiscJSDoc.ts @@ -128,3 +128,198 @@ export class ObserverDoc { 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 Use merge and then map with non-RxJS observable + * 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 Use combineLatest with ES6 Promise + * 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 { + +} + +/** + * `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 Use merge with arrays + * 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 Use merge with array-like + * 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 Use merge with an Iterable (Map) + * 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 { + +} diff --git a/src/observable/DeferObservable.ts b/src/observable/DeferObservable.ts index 17bff114c03..7bf6234cc4f 100644 --- a/src/observable/DeferObservable.ts +++ b/src/observable/DeferObservable.ts @@ -47,7 +47,7 @@ export class DeferObservable extends Observable { * * @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. diff --git a/src/observable/FromObservable.ts b/src/observable/FromObservable.ts index 03d9306639f..a02bb4c79eb 100644 --- a/src/observable/FromObservable.ts +++ b/src/observable/FromObservable.ts @@ -72,12 +72,12 @@ export class FromObservable extends Observable { * @see {@link fromEventPattern} * @see {@link fromPromise} * - * @param {ObservableInput} 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} 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 diff --git a/src/observable/combineLatest.ts b/src/observable/combineLatest.ts index 2f152c5d5f5..daa903d0c7e 100644 --- a/src/observable/combineLatest.ts +++ b/src/observable/combineLatest.ts @@ -61,9 +61,9 @@ export function combineLatest(...observables: Array | (( * @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. diff --git a/src/operator/audit.ts b/src/operator/audit.ts index e9caef09919..41a14bd6522 100644 --- a/src/operator/audit.ts +++ b/src/operator/audit.ts @@ -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} An Observable that performs rate-limiting of diff --git a/src/operator/combineLatest.ts b/src/operator/combineLatest.ts index d06d1dfa246..6c8da167974 100644 --- a/src/operator/combineLatest.ts +++ b/src/operator/combineLatest.ts @@ -58,7 +58,7 @@ export function combineLatest(this: Observable, 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. diff --git a/src/operator/concat.ts b/src/operator/concat.ts index 1e1a32313f7..5f387b13108 100644 --- a/src/operator/concat.ts +++ b/src/operator/concat.ts @@ -55,7 +55,7 @@ export function concat(this: Observable, ...observables: Array(...observables: (ObservableInput | 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. diff --git a/src/operator/concatMap.ts b/src/operator/concatMap.ts index 1fdb1807d03..e692efbea8b 100644 --- a/src/operator/concatMap.ts +++ b/src/operator/concatMap.ts @@ -47,7 +47,7 @@ export function concatMap(this: Observable, 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] diff --git a/src/operator/concatMapTo.ts b/src/operator/concatMapTo.ts index e1b468c1f2d..ac86335a2b6 100644 --- a/src/operator/concatMapTo.ts +++ b/src/operator/concatMapTo.ts @@ -46,7 +46,7 @@ export function concatMapTo(this: Observable, 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 diff --git a/src/operator/debounce.ts b/src/operator/debounce.ts index 1520fe067f0..d19d508d26d 100644 --- a/src/operator/debounce.ts +++ b/src/operator/debounce.ts @@ -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 diff --git a/src/operator/exhaustMap.ts b/src/operator/exhaustMap.ts index 6f65db9ff63..bd50b0e384f 100644 --- a/src/operator/exhaustMap.ts +++ b/src/operator/exhaustMap.ts @@ -39,7 +39,7 @@ export function exhaustMap(this: Observable, 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] diff --git a/src/operator/merge.ts b/src/operator/merge.ts index 1a34d10db47..14bbe5d6154 100644 --- a/src/operator/merge.ts +++ b/src/operator/merge.ts @@ -56,7 +56,7 @@ export function merge(this: Observable, ...observables: Array(...observables: (ObservableInput | 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 diff --git a/src/operator/mergeMap.ts b/src/operator/mergeMap.ts index 89f64936da1..9a274f7c08e 100644 --- a/src/operator/mergeMap.ts +++ b/src/operator/mergeMap.ts @@ -49,7 +49,7 @@ export function mergeMap(this: Observable, 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] diff --git a/src/operator/mergeMapTo.ts b/src/operator/mergeMapTo.ts index 5fc173e7012..0f64215d273 100644 --- a/src/operator/mergeMapTo.ts +++ b/src/operator/mergeMapTo.ts @@ -37,7 +37,7 @@ export function mergeMapTo(this: Observable, 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 diff --git a/src/operator/switchMap.ts b/src/operator/switchMap.ts index b789f1dc78e..1dc65f3708d 100644 --- a/src/operator/switchMap.ts +++ b/src/operator/switchMap.ts @@ -40,7 +40,7 @@ export function switchMap(this: Observable, 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] diff --git a/src/operator/switchMapTo.ts b/src/operator/switchMapTo.ts index 80bf3f6158c..dcc03481082 100644 --- a/src/operator/switchMapTo.ts +++ b/src/operator/switchMapTo.ts @@ -36,7 +36,7 @@ export function switchMapTo(this: Observable, 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 diff --git a/src/operator/throttle.ts b/src/operator/throttle.ts index fc352ad71b3..a3e06488a5b 100644 --- a/src/operator/throttle.ts +++ b/src/operator/throttle.ts @@ -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} An Observable that performs the throttle operation to diff --git a/src/operator/withLatestFrom.ts b/src/operator/withLatestFrom.ts index dc4777b66ef..72b2f224084 100644 --- a/src/operator/withLatestFrom.ts +++ b/src/operator/withLatestFrom.ts @@ -47,7 +47,7 @@ export function withLatestFrom(this: Observable, 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