MiscJSDoc.ts
15.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
/*
* This file and its definitions are needed just so that ESDoc sees these
* JSDoc documentation comments. Originally they were meant for some TypeScript
* interfaces, but TypeScript strips away JSDoc comments near interfaces. Hence,
* we need these bogus classes, which are not stripped away. This file on the
* other hand, is not included in the release bundle.
*/
import { Observer, TeardownLogic } from './internal/types';
import { Observable } from './internal/Observable';
import './internal/observable/dom/MiscJSDoc';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class ObservableDoc {
/**
* Creates a new Observable, that will execute the specified function when an
* {@link Observer} subscribes to it.
*
* <span class="informal">Create custom Observable, that does whatever you like.</span>
*
* ![](create.png)
*
* `create` converts an `onSubscription` function to an actual Observable.
* Whenever someone subscribes to that Observable, the function will be called
* with an {@link Observer} instance as a first and only parameter. `onSubscription` should
* then invoke the Observers `next`, `error` and `complete` methods.
*
* Calling `next` with a value will emit that value to the observer. Calling `complete`
* means that Observable finished emitting and will not do anything else.
* Calling `error` means that something went wrong - value passed to `error` method should
* provide details on what exactly happened.
*
* A well-formed Observable can emit as many values as it needs via `next` method,
* but `complete` and `error` methods can be called only once and nothing else can be called
* thereafter. If you try to invoke `next`, `complete` or `error` methods after created
* Observable already completed or ended with an error, these calls will be ignored to
* preserve so called *Observable Contract*. Note that you are not required to call
* `complete` at any point - it is perfectly fine to create an Observable that never ends,
* depending on your needs.
*
* `onSubscription` can optionally return either a function or an object with
* `unsubscribe` method. In both cases function or method will be called when
* subscription to Observable is being cancelled and should be used to clean up all
* resources. So, for example, if you are using `setTimeout` in your custom
* Observable, when someone unsubscribes, you can clear planned timeout, so that
* it does not fire needlessly and browser (or other environment) does not waste
* computing power on timing event that no one will listen to anyways.
*
* Most of the times you should not need to use `create`, because existing
* operators allow you to create an Observable for most of the use cases.
* That being said, `create` is low-level mechanism allowing you to create
* any Observable, if you have very specific needs.
*
* **TypeScript signature issue**
*
* Because Observable extends class which already has defined static `create` function,
* but with different type signature, it was impossible to assign proper signature to
* `Observable.create`. Because of that, it has very general type `Function` and thus
* function passed to `create` will not be type checked, unless you explicitly state
* what signature it should have.
*
* When using TypeScript we recommend to declare type signature of function passed to
* `create` as `(observer: Observer) => TeardownLogic`, where {@link Observer}
* and {@link TeardownLogic} are interfaces provided by the library.
*
* @example <caption>Emit three numbers, then complete.</caption>
* var observable = Rx.Observable.create(function (observer) {
* observer.next(1);
* observer.next(2);
* observer.next(3);
* observer.complete();
* });
* observable.subscribe(
* value => console.log(value),
* err => {},
* () => console.log('this is the end')
* );
*
* // Logs
* // 1
* // 2
* // 3
* // "this is the end"
*
*
* @example <caption>Emit an error</caption>
* const observable = Rx.Observable.create((observer) => {
* observer.error('something went really wrong...');
* });
*
* observable.subscribe(
* value => console.log(value), // will never be called
* err => console.log(err),
* () => console.log('complete') // will never be called
* );
*
* // Logs
* // "something went really wrong..."
*
*
* @example <caption>Return unsubscribe function</caption>
*
* const observable = Rx.Observable.create(observer => {
* const id = setTimeout(() => observer.next('...'), 5000); // emit value after 5s
*
* return () => { clearTimeout(id); console.log('cleared!'); };
* });
*
* const subscription = observable.subscribe(value => console.log(value));
*
* setTimeout(() => subscription.unsubscribe(), 3000); // cancel subscription after 3s
*
* // Logs:
* // "cleared!" after 3s
*
* // Never logs "..."
*
*
* @see {@link empty}
* @see {@link never}
* @see {@link of}
* @see {@link throw}
*
* @param {function(observer: Observer): TeardownLogic} onSubscription A
* function that accepts an Observer, and invokes its `next`,
* `error`, and `complete` methods as appropriate, and optionally returns some
* logic for cleaning up resources.
* @return {Observable} An Observable that, whenever subscribed, will execute the
* specified function.
* @static true
* @name create
* @owner Observable
* @nocollapse
*/
static create<T>(onSubscription: <R>(observer: Observer<R>) => TeardownLogic): Observable<T> {
return new Observable<T>(onSubscription);
}
}
/**
* An interface for a consumer of push-based notifications delivered by an
* {@link Observable}.
*
* ```ts
* interface Observer<T> {
* closed?: boolean;
* next: (value: T) => void;
* error: (err: any) => void;
* complete: () => void;
* }
* ```
*
* An object conforming to the Observer interface is usually
* given to the `observable.subscribe(observer)` method, and the Observable will
* call the Observer's `next(value)` method to provide notifications. A
* well-behaved Observable will call an Observer's `complete()` method exactly
* once or the Observer's `error(err)` method exactly once, as the last
* notification delivered.
*
* @interface
* @name Observer
* @noimport true
*/
export class ObserverDoc<T> {
/**
* An optional flag to indicate whether this Observer, when used as a
* subscriber, has already been unsubscribed from its Observable.
* @type {boolean}
*/
closed: boolean = false;
/**
* The callback to receive notifications of type `next` from the Observable,
* with a value. The Observable may call this method 0 or more times.
* @param {T} value The `next` value.
* @return {void}
*/
next(value: T): void {
return void 0;
}
/**
* The callback to receive notifications of type `error` from the Observable,
* with an attached {@link Error}. Notifies the Observer that the Observable
* has experienced an error condition.
* @param {any} err The `error` exception.
* @return {void}
*/
error(err: any): void {
return void 0;
}
/**
* The callback to receive a valueless notification of type `complete` from
* the Observable. Notifies the Observer that the Observable has finished
* sending push-based notifications.
* @return {void}
*/
complete(): void {
return void 0;
}
}
/**
* `SubscribableOrPromise` interface describes values that behave like either
* Observables or Promises. 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 this issue is resolved, 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 either an
* {@link SubscribableOrPromise} or some kind of collection of values that
* can be transformed to Observable emitting that values. 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} with following types:
*
* ## 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.
*
*
* @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!"
*
* @example <caption>Use from with generator (returning infinite iterator)</caption>
* // infinite stream of incrementing numbers
* const infinite = function* () {
* let i = 0;
*
* while (true) {
* yield i++;
* }
* };
*
* Rx.Observable.from(infinite())
* .take(3) // only take 3, cause this is infinite
* .subscribe(
* value => console.log(value),
* err => {},
* () => console.log('ta dam!')
* );
*
* // Logs
* // 0
* // 1
* // 2
* // "ta dam!"
*
* @interface
* @name ObservableInput
* @noimport true
*/
export class ObservableInputDoc<T> {
}
/**
*
* This interface describes what should be returned by function passed to Observable
* constructor or static {@link create} function. Value of that interface will be used
* to cancel subscription for given Observable.
*
* `TeardownLogic` can be:
*
* ## Function
*
* Function that takes no parameters. When consumer of created Observable calls `unsubscribe`,
* that function will be called
*
* ## AnonymousSubscription
*
* `AnonymousSubscription` is simply an object with `unsubscribe` method on it. That method
* will work the same as function
*
* ## void
*
* If created Observable does not have any resources to clean up, function does not have to
* return anything.
*
* @interface
* @name TeardownLogic
* @noimport true
*/
export class TeardownLogicDoc {
}