diff --git a/modules/@angular/common/src/pipes/async_pipe.ts b/modules/@angular/common/src/pipes/async_pipe.ts index b923d6e11f..29bc5cb487 100644 --- a/modules/@angular/common/src/pipes/async_pipe.ts +++ b/modules/@angular/common/src/pipes/async_pipe.ts @@ -8,7 +8,7 @@ import {ChangeDetectorRef, OnDestroy, Pipe, PipeTransform, WrappedValue} from '@angular/core'; import {EventEmitter, Observable} from '../facade/async'; -import {isPromise} from '../private_import_core'; +import {isObservable, isPromise} from '../private_import_core'; import {InvalidPipeArgumentError} from './invalid_pipe_argument_error'; interface SubscriptionStrategy { @@ -116,7 +116,7 @@ export class AsyncPipe implements OnDestroy, PipeTransform { return _promiseStrategy; } - if ((obj).subscribe) { + if (isObservable(obj)) { return _observableStrategy; } diff --git a/modules/@angular/common/src/private_import_core.ts b/modules/@angular/common/src/private_import_core.ts index 0292fbf02f..8de9d5f09f 100644 --- a/modules/@angular/common/src/private_import_core.ts +++ b/modules/@angular/common/src/private_import_core.ts @@ -9,3 +9,4 @@ import {__core_private__ as r} from '@angular/core'; export const isPromise: typeof r.isPromise = r.isPromise; +export const isObservable: typeof r.isObservable = r.isObservable; diff --git a/modules/@angular/core/src/core_private_export.ts b/modules/@angular/core/src/core_private_export.ts index e88e11c975..c39c0e5229 100644 --- a/modules/@angular/core/src/core_private_export.ts +++ b/modules/@angular/core/src/core_private_export.ts @@ -41,7 +41,7 @@ import * as reflector_reader from './reflection/reflector_reader'; import * as reflection_types from './reflection/types'; import * as api from './render/api'; import * as decorators from './util/decorators'; -import {isPromise} from './util/lang'; +import {isObservable, isPromise} from './util/lang'; export const __core_private__: { isDefaultChangeDetectionStrategy: typeof constants.isDefaultChangeDetectionStrategy, @@ -107,6 +107,7 @@ export const __core_private__: { _ComponentStillLoadingError?: ComponentStillLoadingError, ComponentStillLoadingError: typeof ComponentStillLoadingError, isPromise: typeof isPromise, + isObservable: typeof isObservable, AnimationTransition: typeof AnimationTransition view_utils: typeof view_utils, } = { @@ -157,5 +158,6 @@ export const __core_private__: { FILL_STYLE_FLAG: FILL_STYLE_FLAG_, ComponentStillLoadingError: ComponentStillLoadingError, isPromise: isPromise, + isObservable: isObservable, AnimationTransition: AnimationTransition }; diff --git a/modules/@angular/core/src/util/lang.ts b/modules/@angular/core/src/util/lang.ts index 6cf4316a83..127b47734a 100644 --- a/modules/@angular/core/src/util/lang.ts +++ b/modules/@angular/core/src/util/lang.ts @@ -6,6 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import {Observable} from 'rxjs/Observable'; +import {$$observable as symbolObservable} from 'rxjs/symbol/observable'; + /** * Determine if the argument is shaped like a Promise */ @@ -14,3 +17,10 @@ export function isPromise(obj: any): obj is Promise { // It's up to the caller to ensure that obj.then conforms to the spec return !!obj && typeof obj.then === 'function'; } + +/** + * Determine if the argument is an Observable + */ +export function isObservable(obj: any | Observable): obj is Observable { + return !!(obj && obj[symbolObservable]); +} diff --git a/modules/@angular/core/test/util/lang_spec.ts b/modules/@angular/core/test/util/lang_spec.ts index 961a3fd6da..e8ee79f13b 100644 --- a/modules/@angular/core/test/util/lang_spec.ts +++ b/modules/@angular/core/test/util/lang_spec.ts @@ -5,7 +5,8 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {isPromise} from '@angular/core/src/util/lang'; +import {isObservable, isPromise} from '@angular/core/src/util/lang'; +import {of } from 'rxjs/observable/of'; export function main() { describe('isPromise', () => { @@ -25,4 +26,22 @@ export function main() { expect(isPromise(null)).toEqual(false); }); }); + + describe('isObservable', () => { + it('should be true for an Observable', () => expect(isObservable(of (true))).toEqual(true)); + + it('should be false if the argument is undefined', + () => expect(isObservable(undefined)).toEqual(false)); + + it('should be false if the argument is null', () => expect(isObservable(null)).toEqual(false)); + + it('should be false if the argument is an object', + () => expect(isObservable({})).toEqual(false)); + + it('should be false if the argument is a function', + () => expect(isObservable(() => {})).toEqual(false)); + + it('should be false if the argument is the object with subscribe function', + () => expect(isObservable({subscribe: () => {}})).toEqual(false)); + }); } diff --git a/modules/@angular/router/src/private_import_core.ts b/modules/@angular/router/src/private_import_core.ts new file mode 100644 index 0000000000..8de9d5f09f --- /dev/null +++ b/modules/@angular/router/src/private_import_core.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {__core_private__ as r} from '@angular/core'; + +export const isPromise: typeof r.isPromise = r.isPromise; +export const isObservable: typeof r.isObservable = r.isObservable; diff --git a/modules/@angular/router/src/utils/collection.ts b/modules/@angular/router/src/utils/collection.ts index 4bafad0cf4..779520244e 100644 --- a/modules/@angular/router/src/utils/collection.ts +++ b/modules/@angular/router/src/utils/collection.ts @@ -16,6 +16,7 @@ import * as l from 'rxjs/operator/last'; import {map} from 'rxjs/operator/map'; import {mergeAll} from 'rxjs/operator/mergeAll'; +import {isObservable, isPromise} from '../private_import_core'; import {PRIMARY_OUTLET} from '../shared'; export function shallowEqualArrays(a: any[], b: any[]): boolean { @@ -129,11 +130,11 @@ export function andObservables(observables: Observable>): Observ export function wrapIntoObservable(value: T | NgModuleFactory| Promise| Observable): Observable { - if (value instanceof Observable) { + if (isObservable(value)) { return value; } - if (value instanceof Promise) { + if (isPromise(value)) { return fromPromise(value); }