Skip to content

Commit 468303a

Browse files
authored
fix(toObservableValue): accommodate all observable inputs (#2471)
- Switches toObservableValue to just use rxjs `from`. This will ensure it works with all types that `rxjs` is compatable with. Also, the checks in `toObservableValue` were redundant if `from` was used. For example, if `x` is `Observable` from rxjs, then `from(x) === x` would be `true`. `from` does all of the necessary checks. Also, `from` will do the work of figuring out of it happens to be an observable that has interop with RxJS, or is an observable from another instance of rxjs (in node_modules, Node scenario). - Also `x == null` will only return `true` if `x` is `undefined` or `null`. - Fixes the return types of `toObservableValue` to be more true to form. If you return `Observable<X> | Observable<Y> | Observable<Z>`, it's really no different than `Observable<X | Y | Z>`, because there's no static/synchronous way to narrow the type of the `Observable` to say, `Observable<X>` in either scenario. - Removes unecessary types in favor of more obvious explicit types - Removes superfluous isObservable-type assert function - Removes unused assertion methods. Not sure what those were used for, as they were exported, but two were ill-advised, as they were doing type-narrowing by iterating over an array, making it an O(n) operation just to narrow a type.
1 parent 19f1bda commit 468303a

File tree

5 files changed

+18
-88
lines changed

5 files changed

+18
-88
lines changed

modules/component/spec/core/projections/toObservableValue.spec.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import { EMPTY, isObservable, Observable, of } from 'rxjs';
1+
import { EMPTY, isObservable, Observable } from 'rxjs';
22
import { toObservableValue } from '../../../src/core/projections';
33

44
describe('toObservableValue', () => {
55
describe('used as RxJS creation function', () => {
6+
// NOTE: (benlesh) These tests are probably all redundant, as you're just
7+
// testing `rxjs` from in every case but `null` and `undefined`.
8+
69
it('should take observables', () => {
710
const observable: Observable<any> = toObservableValue(EMPTY);
811
expect(isObservable(observable)).toBe(true);
@@ -15,6 +18,12 @@ describe('toObservableValue', () => {
1518
expect(isObservable(observable)).toBe(true);
1619
});
1720

21+
it('should take an iterable', () => {
22+
const set = new Set([1, 2, 3]);
23+
const observable: Observable<any> = toObservableValue(set.values());
24+
expect(isObservable(observable)).toBe(true);
25+
});
26+
1827
it('should take undefined', () => {
1928
const observable: Observable<any> = toObservableValue(undefined);
2029
expect(isObservable(observable)).toBe(true);
@@ -25,7 +34,9 @@ describe('toObservableValue', () => {
2534
expect(isObservable(observable)).toBe(true);
2635
});
2736

28-
it('throw if no observable, promise, undefined or null is passed', () => {
37+
// NOTE: (benlesh) - AFIACT this test would never have passed with the existing code
38+
// `toObservableValue(null)` was made to return `of(null)`
39+
xit('throw if no observable, promise, undefined or null is passed', () => {
2940
const observable: Observable<any> = toObservableValue(null);
3041
observable.subscribe({
3142
error(e) {

modules/component/src/core/cd-aware.abstract.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export function createCdAware<U>(cfg: {
6161
// Ignore potential observables of the same instances
6262
distinctUntilChanged(),
6363
// Try to convert it to values, throw if not possible
64-
map(v => toObservableValue(v)),
64+
map(toObservableValue),
6565
tap((v: any) => {
6666
cfg.resetContextObserver.next(v);
6767
cfg.work();
Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,7 @@
1-
import { from, of } from 'rxjs';
2-
import {
3-
isObservableGuard,
4-
isPromiseGuard,
5-
PotentialObservableValue,
6-
Output,
7-
} from '../utils';
1+
import { from, of, Observable, ObservableInput } from 'rxjs';
82

93
export function toObservableValue<T>(
10-
p: PotentialObservableValue<T>
11-
): Output<T> {
12-
// Comparing to the literal null value with the == operator covers both null and undefined values.
13-
if (p === null) {
14-
return of(p);
15-
}
16-
17-
if (p === undefined) {
18-
return of(p);
19-
}
20-
21-
if (isObservableGuard<T>(p)) {
22-
return p;
23-
}
24-
25-
if (isPromiseGuard<T>(p)) {
26-
return from(p);
27-
}
28-
29-
throw new Error(
30-
'Argument not observable. Only null/undefined or Promise/Observable-like values are allowed.'
31-
);
4+
p: ObservableInput<T> | undefined | null
5+
): Observable<T | undefined | null> {
6+
return p == null ? of(p) : from(p);
327
}

modules/component/src/core/utils/index.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,3 @@ export { getChangeDetectionHandler } from './get-change-detection-handling';
22
export { getGlobalThis } from './get-global-this';
33
export { isIvy } from './is-ivy';
44
export { hasZone } from './has-zone';
5-
6-
export {
7-
isDefinedGuard,
8-
isIterableGuard,
9-
isObservableGuard,
10-
isOperateFnArrayGuard,
11-
isPromiseGuard,
12-
isStringArrayGuard,
13-
PotentialObservableValue,
14-
Output,
15-
} from './typing';

modules/component/src/core/utils/typing.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

0 commit comments

Comments
 (0)