diff --git a/package.json b/package.json index 2010057e08..dcb1eb26bd 100644 --- a/package.json +++ b/package.json @@ -70,9 +70,9 @@ "copy_src_cjs": "mkdirp ./dist/cjs/src && cp -r ./src/* ./dist/cjs/src", "copy_src_es6": "mkdirp ./dist/es6/src && cp -r ./src/* ./dist/es6/src", "commit": "git-cz", - "compile_dist_amd": "tsc typings/main/ambient/es6-shim/index.d.ts ./dist/amd/src/Rx.ts ./dist/amd/src/Rx.KitchenSink.ts ./dist/amd/src/Rx.DOM.ts ./dist/amd/src/add/observable/of.ts -m amd --sourceMap --outDir ./dist/amd --target ES5 --diagnostics --pretty --noImplicitAny --suppressImplicitAnyIndexErrors", - "compile_dist_cjs": "tsc typings/main/ambient/es6-shim/index.d.ts ./dist/cjs/src/Rx.ts ./dist/cjs/src/Rx.KitchenSink.ts ./dist/cjs/src/Rx.DOM.ts ./dist/cjs/src/add/observable/of.ts -m commonjs --sourceMap --outDir ./dist/cjs --target ES5 -d --diagnostics --pretty --noImplicitAny --suppressImplicitAnyIndexErrors", - "compile_dist_es6": "tsc ./dist/es6/src/Rx.ts ./dist/es6/src/Rx.KitchenSink.ts ./dist/es6/src/Rx.DOM.ts ./dist/es6/src/add/observable/of.ts -m es2015 --sourceMap --outDir ./dist/es6 --target ES6 -d --diagnostics --pretty --noImplicitAny --suppressImplicitAnyIndexErrors", + "compile_dist_amd": "tsc typings/main/ambient/es6-shim/index.d.ts ./spec/es5.d.ts ./dist/amd/src/Rx.ts ./dist/amd/src/Rx.KitchenSink.ts ./dist/amd/src/Rx.DOM.ts ./dist/amd/src/add/observable/of.ts -m amd --sourceMap --outDir ./dist/amd --target ES5 --diagnostics --pretty --noImplicitAny --suppressImplicitAnyIndexErrors", + "compile_dist_cjs": "tsc typings/main/ambient/es6-shim/index.d.ts ./spec/es5.d.ts ./dist/cjs/src/Rx.ts ./dist/cjs/src/Rx.KitchenSink.ts ./dist/cjs/src/Rx.DOM.ts ./dist/cjs/src/add/observable/of.ts -m commonjs --sourceMap --outDir ./dist/cjs --target ES5 -d --diagnostics --pretty --noImplicitAny --suppressImplicitAnyIndexErrors", + "compile_dist_es6": "tsc ./dist/es6/src/Rx.ts ./dist/es6/src/Rx.KitchenSink.ts ./dist/es6/src/Rx.DOM.ts ./dist/es6/src/add/observable/of.ts -m es2015 --sourceMap --outDir ./dist/es6 --target ES6 -d --diagnostics --pretty --noImplicitAny --suppressImplicitAnyIndexErrors", "cover": "npm-run-all cover_test cover_remapping", "cover_test": "rm -rf dist/cjs && tsc typings/main/ambient/es6-shim/index.d.ts src/Rx.ts src/Rx.KitchenSink.ts src/Rx.DOM.ts src/add/observable/of.ts -m commonjs --outDir dist/cjs --sourceMap --target ES5 -d && istanbul cover -x \"spec-js/**/*\" ./node_modules/mocha/bin/_mocha -- --opts spec/support/default.opts spec-js", "cover_remapping": "remap-istanbul -i coverage/coverage.json -o coverage/coverage-remapped.json && remap-istanbul -i coverage/coverage.json -o coverage/coverage-remapped.lcov -t lcovonly && remap-istanbul -i coverage/coverage.json -o coverage/coverage-remapped -t html", diff --git a/spec/es5.d.ts b/spec/es5.d.ts new file mode 100644 index 0000000000..2c66099c45 --- /dev/null +++ b/spec/es5.d.ts @@ -0,0 +1,13 @@ +interface Symbol { } +interface SymbolConstructor { + iterator: symbol; +} +declare var Symbol: SymbolConstructor; +interface Iterable { + [Symbol.iterator](): Iterator; +} +interface Iterator { + next(value?: any): IteratorResult; + return?(value?: any): IteratorResult; + throw?(e?: any): IteratorResult; +} diff --git a/spec/observables/from-spec.ts b/spec/observables/from-spec.ts index 31604878da..dd0b2cf4a3 100644 --- a/spec/observables/from-spec.ts +++ b/spec/observables/from-spec.ts @@ -1,8 +1,9 @@ import {expect} from 'chai'; import * as Rx from '../../dist/cjs/Rx.KitchenSink'; import {$$iterator} from '../../dist/cjs/symbol/iterator'; +import {Observablesque} from '../../dist/cjs/Observable'; -declare const {expectObservable, Symbol}; +declare const {expectObservable, Symbol, type}; declare const rxTestScheduler: Rx.TestScheduler; const Observable = Rx.Observable; @@ -26,7 +27,7 @@ describe('Observable.from', () => { it('should handle an ArrayLike', function (done: MochaDone) { this.timeout(300); - const arrayLike = { + const arrayLike: ArrayLike = { length: 3, 0: 1, 1: 2, @@ -64,7 +65,7 @@ describe('Observable.from', () => { it('should handle an ArrayLike with a mapFn', function (done: MochaDone) { this.timeout(300); - const arrayLike = { + const arrayLike: ArrayLike = { length: 3, 0: 1, 1: 2, @@ -83,7 +84,7 @@ describe('Observable.from', () => { }); it('should handle an ArrayLike with a thisArg', (done: MochaDone) => { - const arrayLike = { + const arrayLike: ArrayLike = { length: 3, 0: 1, 1: 2, @@ -116,7 +117,7 @@ describe('Observable.from', () => { }); it('should handle an "observableque" object', (done: MochaDone) => { - const observablesque = {}; + const observablesque: Observablesque = {}; observablesque[Symbol.observable] = () => { return { @@ -137,7 +138,7 @@ describe('Observable.from', () => { }); it('should accept scheduler for observableque object', () => { - const observablesque = {}; + const observablesque: Observablesque = {}; observablesque[Symbol.observable] = () => { return { @@ -166,7 +167,7 @@ describe('Observable.from', () => { }); it('should handle any iterable thing', (done: MochaDone) => { - const iterable = {}; + const iterable: Iterable = {}; const iteratorResults = [ { value: 'one', done: false }, { value: 'two', done: false }, @@ -195,7 +196,7 @@ describe('Observable.from', () => { it('should throw for non observable object', () => { const r = () => { - Observable.from({}).subscribe(); + Observable.from({}).subscribe(); }; expect(r).to.throw(); @@ -212,4 +213,23 @@ describe('Observable.from', () => { done(); }); }); + + it('should return T for ObservableLike objects', () => { + type(() => { + /* tslint:disable:no-unused-variable */ + let o1: Rx.Observable = Observable.from([], Rx.Scheduler.asap); + let o2: Rx.Observable = Observable.from(>{}); + let o3: Rx.Observable<{ a: string }> = Observable.from(Observable.empty<{ a: string }>()); + let o4: Rx.Observable<{ b: number }> = Observable.from(new Promise<{b: number}>(resolve => resolve())); + /* tslint:enable:no-unused-variable */ + }); + }); + + it('should return T and map for arrays', () => { + type(() => { + /* tslint:disable:no-unused-variable */ + let o1: Rx.Observable = Observable.from([], x => x.toString(), null, Rx.Scheduler.asap); + /* tslint:enable:no-unused-variable */ + }); + }); }); diff --git a/spec/observables/zip-spec.ts b/spec/observables/zip-spec.ts index a036c88dd3..e9ef4d4d5a 100644 --- a/spec/observables/zip-spec.ts +++ b/spec/observables/zip-spec.ts @@ -77,7 +77,7 @@ describe('Observable.zip', () => { describe('with iterables', () => { it('should zip them with values', () => { - const myIterator = { + const myIterator: Iterable = { count: 0, next: function () { return { value: this.count++, done: false }; @@ -103,7 +103,7 @@ describe('Observable.zip', () => { it('should only call `next` as needed', () => { let nextCalled = 0; - const myIterator = { + const myIterator: Iterable = { count: 0, next: () => { nextCalled++; diff --git a/spec/operators/mergeMap-spec.ts b/spec/operators/mergeMap-spec.ts index 0cc11ee0fa..06aef656d0 100644 --- a/spec/operators/mergeMap-spec.ts +++ b/spec/operators/mergeMap-spec.ts @@ -43,7 +43,7 @@ describe('Observable.prototype.mergeMap', () => { it('should map values to constant rejected promises and merge', (done: MochaDone) => { const source = Rx.Observable.from([4, 3, 2, 1]); const project = function (value) { - return Observable.from(Promise.reject(42)); + return Observable.from(Promise.reject(42)); }; source.mergeMap(project).subscribe( @@ -82,11 +82,11 @@ describe('Observable.prototype.mergeMap', () => { it('should map values to rejected promises and merge', (done: MochaDone) => { const source = Rx.Observable.from([4, 3, 2, 1]); const project = function (value, index) { - return Observable.from(Promise.reject('' + value + '-' + index)); + return Observable.from(Promise.reject('' + value + '-' + index)); }; source.mergeMap(project).subscribe( - (x: number) => { + (x: string) => { done(new Error('Subscriber next handler not supposed to be called.')); }, (err: any) => { diff --git a/spec/operators/zip-spec.ts b/spec/operators/zip-spec.ts index 2fc29de552..470a1f64a4 100644 --- a/spec/operators/zip-spec.ts +++ b/spec/operators/zip-spec.ts @@ -77,7 +77,7 @@ describe('Observable.prototype.zip', () => { describe('with iterables', () => { it('should zip them with values', () => { - const myIterator = { + const myIterator: Iterable = { count: 0, next: function () { return { value: this.count++, done: false }; @@ -102,7 +102,7 @@ describe('Observable.prototype.zip', () => { it('should only call `next` as needed', () => { let nextCalled = 0; - const myIterator = { + const myIterator: Iterable = { count: 0, next: function () { nextCalled++; diff --git a/src/Observable.ts b/src/Observable.ts index 42d72f9da1..6852102c80 100644 --- a/src/Observable.ts +++ b/src/Observable.ts @@ -13,9 +13,13 @@ export interface Subscribable { subscribe(observer: Observer): AnonymousSubscription; } -export type SubscribableOrPromise = Subscribable | Promise; -export type ArrayOrIterator = Iterator | ArrayLike; -export type ObservableInput = SubscribableOrPromise | ArrayOrIterator; +export interface Observablesque { + [Symbol.observable](): Subscribable; +} + +export type SubscribableOrPromise = Observablesque | Subscribable | Promise; +export type ArrayOrIterable = Iterable | ArrayLike; +export type ObservableInput = SubscribableOrPromise | ArrayOrIterable; /** * A representation of any set of values over any amount of time. This the most basic building block diff --git a/src/observable/ArrayObservable.ts b/src/observable/ArrayObservable.ts index 688847bb7d..0e5a584e80 100644 --- a/src/observable/ArrayObservable.ts +++ b/src/observable/ArrayObservable.ts @@ -24,7 +24,14 @@ export class ArrayObservable extends Observable { * @name of * @owner Observable */ - static of(...array: Array): Observable { + static of(item1: T, scheduler?: Scheduler): Observable; + static of(item1: T, item2: T, scheduler?: Scheduler): Observable; + static of(item1: T, item2: T, item3: T, scheduler?: Scheduler): Observable; + static of(item1: T, item2: T, item3: T, item4: T, scheduler?: Scheduler): Observable; + static of(item1: T, item2: T, item3: T, item4: T, item5: T, scheduler?: Scheduler): Observable; + static of(item1: T, item2: T, item3: T, item4: T, item5: T, item6: T, scheduler?: Scheduler): Observable; + static of(...array: Array): Observable; + static of(...array: Array): Observable { let scheduler = array[array.length - 1]; if (isScheduler(scheduler)) { array.pop(); diff --git a/src/observable/FromObservable.ts b/src/observable/FromObservable.ts index 4f0981aa36..5f5d1cc768 100644 --- a/src/observable/FromObservable.ts +++ b/src/observable/FromObservable.ts @@ -36,7 +36,12 @@ export class FromObservable extends Observable { * @name from * @owner Observable */ - static create(ish: any, mapFnOrScheduler?: Scheduler | ((x: any, y: number) => T), thisArg?: any, lastScheduler?: Scheduler): Observable { + static create(ish: ObservableInput, scheduler?: Scheduler): Observable; + static create(ish: ArrayLike, mapFn: (x: any, y: number) => R, thisArg?: any, scheduler?: Scheduler): Observable; + static create(ish: ObservableInput, + mapFnOrScheduler?: Scheduler | ((x: any, y: number) => T), + thisArg?: any, + lastScheduler?: Scheduler): Observable { let scheduler: Scheduler = null; let mapFn: (x: any, i: number) => T = null; if (isFunction(mapFnOrScheduler)) { diff --git a/src/symbol/observable.ts b/src/symbol/observable.ts index fe2173b9d1..39be6b41d5 100644 --- a/src/symbol/observable.ts +++ b/src/symbol/observable.ts @@ -1,8 +1,9 @@ +/// import {root} from '../util/root'; -const Symbol: any = root.Symbol; +const Symbol = root.Symbol; -export let $$observable: any; +export let $$observable: symbol; if (typeof Symbol === 'function') { if (Symbol.observable) { @@ -16,5 +17,5 @@ if (typeof Symbol === 'function') { Symbol.observable = $$observable; } } else { - $$observable = '@@observable'; + $$observable = '@@observable'; } diff --git a/src/symbol/symbol.d.ts b/src/symbol/symbol.d.ts new file mode 100644 index 0000000000..45f7582e36 --- /dev/null +++ b/src/symbol/symbol.d.ts @@ -0,0 +1,3 @@ +declare interface SymbolConstructor { + observable: symbol; +} diff --git a/src/util/subscribeToResult.ts b/src/util/subscribeToResult.ts index 0832f9338a..9f35f47179 100644 --- a/src/util/subscribeToResult.ts +++ b/src/util/subscribeToResult.ts @@ -2,7 +2,7 @@ import {root} from './root'; import {isArray} from './isArray'; import {isPromise} from './isPromise'; import {Subscriber} from '../Subscriber'; -import {Observable} from '../Observable'; +import {Observable, ObservableInput} from '../Observable'; import {$$iterator} from '../symbol/iterator'; import {$$observable} from '../symbol/observable'; import {Subscription} from '../Subscription'; @@ -12,8 +12,12 @@ import {OuterSubscriber} from '../OuterSubscriber'; export function subscribeToResult(outerSubscriber: OuterSubscriber, result: any, outerValue?: T, - outerIndex?: number): Subscription { - let destination: Subscriber = new InnerSubscriber(outerSubscriber, outerValue, outerIndex); + outerIndex?: number): Subscription; +export function subscribeToResult(outerSubscriber: OuterSubscriber, + result: ObservableInput, + outerValue?: T, + outerIndex?: number): Subscription { + let destination: Subscriber = new InnerSubscriber(outerSubscriber, outerValue, outerIndex); if (destination.isUnsubscribed) { return; @@ -21,7 +25,7 @@ export function subscribeToResult(outerSubscriber: OuterSubscriber, if (result instanceof Observable) { if (result._isScalar) { - destination.next(result.value); + destination.next((result).value); destination.complete(); return; } else { @@ -38,9 +42,9 @@ export function subscribeToResult(outerSubscriber: OuterSubscriber, } } else if (isPromise(result)) { result.then( - (value: any) => { + (value) => { if (!destination.isUnsubscribed) { - destination.next(value); + destination.next(value); destination.complete(); } }, @@ -52,8 +56,8 @@ export function subscribeToResult(outerSubscriber: OuterSubscriber, }); return destination; } else if (typeof result[$$iterator] === 'function') { - for (let item of result) { - destination.next(item); + for (let item of result) { + destination.next(item); if (destination.isUnsubscribed) { break; }