diff --git a/spec/operators/first-spec.ts b/spec/operators/first-spec.ts index b00dc591e3..6abad29eee 100644 --- a/spec/operators/first-spec.ts +++ b/spec/operators/first-spec.ts @@ -42,6 +42,20 @@ describe('Observable.prototype.first', () => { expectSubscriptions(e1.subscriptions).toBe(sub); }); + it('should only emit one value in recursive cases', () => { + const subject = new Rx.Subject(); + const results = []; + + subject.first().subscribe(x => { + results.push(x); + subject.next(x + 1); + }); + + subject.next(0); + + expect(results).to.deep.equal([0]); + }); + it('should propagate error from the source observable', () => { const e1 = hot('---^---#'); const expected = '----#'; diff --git a/src/operator/first.ts b/src/operator/first.ts index 73fdf00583..80d442820c 100644 --- a/src/operator/first.ts +++ b/src/operator/first.ts @@ -85,6 +85,7 @@ class FirstOperator implements Operator { class FirstSubscriber extends Subscriber { private index: number = 0; private hasCompleted: boolean = false; + private _emitted: boolean = false; constructor(destination: Subscriber, private predicate?: (value: T, index: number, source: Observable) => boolean, @@ -137,9 +138,12 @@ class FirstSubscriber extends Subscriber { private _emitFinal(value: any) { const destination = this.destination; - destination.next(value); - destination.complete(); - this.hasCompleted = true; + if (!this._emitted) { + this._emitted = true; + destination.next(value); + destination.complete(); + this.hasCompleted = true; + } } protected _complete(): void {