diff --git a/doc/subject.md b/doc/subject.md index 232994d9b4..a58fa3e782 100644 --- a/doc/subject.md +++ b/doc/subject.md @@ -341,3 +341,39 @@ subject.complete(); ``` The AsyncSubject is similar to the [`last()`](../class/es6/Observable.js~Observable.html#instance-method-last) operator, in that it waits for the `complete` notification in order to deliver a single value. + +## Void subject + +Sometimes the emitted value doesn't matter as much as the fact that a value was emitted. + +For instance, the code below signals that one second has passed. + +```ts +const subject = new Subject(); +setTimeout(() => subject.next('dummy'), 1000); +``` + +Passing a dummy value this way is clumsy and can confuse users. + +By declaring a _void subject_, you signal that the value is irrelevant. Only the event itself matters. + +```ts +const subject = new Subject(); +setTimeout(() => subject.next(), 1000); +``` + +A complete example with context is shown below: + +```ts +import { Subject } from 'rxjs'; + +const subject = new Subject(); // Shorthand for Subject + +subject.subscribe({ + next: () => console.log('One second has passed') +}); + +setTimeout(() => subject.next(), 1000); +``` + +Before version 7, the default type of Subject values was `any`. `Subject` disables type checking of the emitted values, whereas `Subject` prevents accidental access to the emitted value. If you want the old behavior, then replace `Subject` with `Subject`. \ No newline at end of file diff --git a/spec/Subject-spec.ts b/spec/Subject-spec.ts index be89a9074a..3f234beafc 100644 --- a/spec/Subject-spec.ts +++ b/spec/Subject-spec.ts @@ -6,6 +6,30 @@ import { delay } from 'rxjs/operators'; /** @test {Subject} */ describe('Subject', () => { + + it('should allow next with empty, undefined or any when created with no type', (done: MochaDone) => { + const subject = new Subject(); + subject.subscribe(x => { + expect(x).to.be.a('undefined'); + }, null, done); + + const data: any = undefined; + subject.next(); + subject.next(undefined); + subject.next(data); + subject.complete(); + }); + + it('should allow empty next when created with void type', (done: MochaDone) => { + const subject = new Subject(); + subject.subscribe(x => { + expect(x).to.be.a('undefined'); + }, null, done); + + subject.next(); + subject.complete(); + }); + it('should pump values right on through itself', (done: MochaDone) => { const subject = new Subject(); const expected = ['foo', 'bar']; @@ -271,7 +295,7 @@ describe('Subject', () => { }); it('should not allow values to be nexted after it is unsubscribed', (done: MochaDone) => { - const subject = new Subject(); + const subject = new Subject(); const expected = ['foo']; subject.subscribe(function (x) { @@ -397,7 +421,7 @@ describe('Subject', () => { it('should be an Observer which can be given to Observable.subscribe', (done: MochaDone) => { const source = of(1, 2, 3, 4, 5); - const subject = new Subject(); + const subject = new Subject(); const expected = [1, 2, 3, 4, 5]; subject.subscribe( @@ -414,7 +438,7 @@ describe('Subject', () => { it('should be usable as an Observer of a finite delayed Observable', (done: MochaDone) => { const source = of(1, 2, 3).pipe(delay(50)); - const subject = new Subject(); + const subject = new Subject(); const expected = [1, 2, 3]; @@ -431,7 +455,7 @@ describe('Subject', () => { }); it('should throw ObjectUnsubscribedError when emit after unsubscribed', () => { - const subject = new Subject(); + const subject = new Subject(); subject.unsubscribe(); expect(() => { diff --git a/spec/observables/from-spec.ts b/spec/observables/from-spec.ts index ee5d6f3d9e..ae44e2d25f 100644 --- a/spec/observables/from-spec.ts +++ b/spec/observables/from-spec.ts @@ -139,8 +139,8 @@ describe('from', () => { expect(nextInvoked).to.equal(false); }); it(`should accept a function`, (done) => { - const subject = new Subject(); - const handler: any = (...args: any[]) => subject.next(...args); + const subject = new Subject(); + const handler: any = (arg: any) => subject.next(arg); handler[observable] = () => subject; let nextInvoked = false; diff --git a/spec/operators/bufferCount-spec.ts b/spec/operators/bufferCount-spec.ts index d57fb43876..3205e75d89 100644 --- a/spec/operators/bufferCount-spec.ts +++ b/spec/operators/bufferCount-spec.ts @@ -45,7 +45,7 @@ describe('bufferCount operator', () => { }); it('should buffer properly (issue #2062)', () => { - const item$ = new Subject(); + const item$ = new Subject(); const results: any[] = []; item$.pipe( bufferCount(3, 1) diff --git a/spec/operators/skipUntil-spec.ts b/spec/operators/skipUntil-spec.ts index d730c2a018..13673bb86c 100644 --- a/spec/operators/skipUntil-spec.ts +++ b/spec/operators/skipUntil-spec.ts @@ -247,7 +247,7 @@ describe('skipUntil', () => { const e1 = hot( '--a--b--c--d--e--|'); const e1subs = ['^ !', '^ !']; // for the explicit subscribe some lines below - const skip = new Subject(); + const skip = new Subject(); const expected = '-----------------|'; e1.subscribe((x: string) => { diff --git a/src/internal/Subject.ts b/src/internal/Subject.ts index c7bb591c57..bd8d7221b7 100644 --- a/src/internal/Subject.ts +++ b/src/internal/Subject.ts @@ -25,7 +25,7 @@ export class SubjectSubscriber extends Subscriber { * * @class Subject */ -export class Subject extends Observable implements SubscriptionLike { +export class Subject extends Observable implements SubscriptionLike { [rxSubscriberSymbol]() { return new SubjectSubscriber(this); @@ -58,7 +58,7 @@ export class Subject extends Observable implements SubscriptionLike { return subject; } - next(value?: T) { + next(value: T) { if (this.closed) { throw new ObjectUnsubscribedError(); } diff --git a/src/internal/operators/repeatWhen.ts b/src/internal/operators/repeatWhen.ts index 8b9c233e65..9b88bf5181 100644 --- a/src/internal/operators/repeatWhen.ts +++ b/src/internal/operators/repeatWhen.ts @@ -60,7 +60,7 @@ class RepeatWhenOperator implements Operator { */ class RepeatWhenSubscriber extends OuterSubscriber { - private notifications: Subject | null = null; + private notifications: Subject | null = null; private retries: Observable | null = null; private retriesSubscription: Subscription | null | undefined = null; private sourceIsBeingSubscribedTo: boolean = true; diff --git a/src/internal/operators/share.ts b/src/internal/operators/share.ts index 6421b1f131..2917a6a980 100644 --- a/src/internal/operators/share.ts +++ b/src/internal/operators/share.ts @@ -6,7 +6,7 @@ import { Subject } from '../Subject'; import { MonoTypeOperatorFunction } from '../types'; function shareSubjectFactory() { - return new Subject(); + return new Subject(); } /** diff --git a/src/internal/operators/windowTime.ts b/src/internal/operators/windowTime.ts index d60fc1bc98..df8e063c2b 100644 --- a/src/internal/operators/windowTime.ts +++ b/src/internal/operators/windowTime.ts @@ -165,7 +165,7 @@ interface CloseState { class CountedSubject extends Subject { private _numberOfNextedValues: number = 0; - next(value?: T): void { + next(value: T): void { this._numberOfNextedValues++; super.next(value); }