Skip to content

Commit

Permalink
fix(publish): fix selector typings
Browse files Browse the repository at this point in the history
Fixes the typings for publish and multicast, so that selectors that
change the observable's type are supported.

Closes #2889
  • Loading branch information
cartant committed Oct 3, 2017
1 parent c7c337e commit 2d58972
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 15 deletions.
24 changes: 24 additions & 0 deletions spec/operators/multicast-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as Rx from '../../dist/package/Rx';
import marbleTestingSignature = require('../helpers/marble-testing'); // tslint:disable-line:no-require-imports

declare const { asDiagram, time, rxTestScheduler };
declare const type;
declare const hot: typeof marbleTestingSignature.hot;
declare const cold: typeof marbleTestingSignature.cold;
declare const expectObservable: typeof marbleTestingSignature.expectObservable;
Expand Down Expand Up @@ -638,4 +639,27 @@ describe('Observable.prototype.multicast', () => {
});
});
});

describe('typings', () => {
type('should infer the type', () => {
/* tslint:disable:no-unused-variable */
const source = Rx.Observable.of<number>(1, 2, 3);
const result: Rx.Observable<number> = source.multicast(() => new Subject<number>());
/* tslint:enable:no-unused-variable */
});

type('should infer the type with a selector', () => {
/* tslint:disable:no-unused-variable */
const source = Rx.Observable.of<number>(1, 2, 3);
const result: Rx.Observable<number> = source.multicast(() => new Subject<number>(), s => s.map(x => x));
/* tslint:enable:no-unused-variable */
});

type('should infer the type with a type-changing selector', () => {
/* tslint:disable:no-unused-variable */
const source = Rx.Observable.of<number>(1, 2, 3);
const result: Rx.Observable<string> = source.multicast(() => new Subject<number>(), s => s.map(x => x + '!'));
/* tslint:enable:no-unused-variable */
});
});
});
22 changes: 22 additions & 0 deletions spec/operators/publish-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as Rx from '../../dist/package/Rx';
import marbleTestingSignature = require('../helpers/marble-testing'); // tslint:disable-line:no-require-imports

declare const { asDiagram };
declare const type;
declare const hot: typeof marbleTestingSignature.hot;
declare const cold: typeof marbleTestingSignature.cold;
declare const expectObservable: typeof marbleTestingSignature.expectObservable;
Expand Down Expand Up @@ -332,4 +333,25 @@ describe('Observable.prototype.publish', () => {
expect(subscriptions).to.equal(1);
done();
});

type('should infer the type', () => {
/* tslint:disable:no-unused-variable */
const source = Rx.Observable.of<number>(1, 2, 3);
const result: Rx.Observable<number> = source.publish();
/* tslint:enable:no-unused-variable */
});

type('should infer the type with a selector', () => {
/* tslint:disable:no-unused-variable */
const source = Rx.Observable.of<number>(1, 2, 3);
const result: Rx.Observable<number> = source.publish(s => s.map(x => x));
/* tslint:enable:no-unused-variable */
});

type('should infer the type with a type-changing selector', () => {
/* tslint:disable:no-unused-variable */
const source = Rx.Observable.of<number>(1, 2, 3);
const result: Rx.Observable<string> = source.publish(s => s.map(x => x + '!'));
/* tslint:enable:no-unused-variable */
});
});
7 changes: 4 additions & 3 deletions src/operator/multicast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Subject } from '../Subject';
import { Observable } from '../Observable';
import { ConnectableObservable } from '../observable/ConnectableObservable';
import { multicast as higherOrder } from '../operators/multicast';
import { FactoryOrValue, MonoTypeOperatorFunction } from '../interfaces';
import { FactoryOrValue, MonoTypeOperatorFunction, OperatorFunction } from '../interfaces';

/* tslint:disable:max-line-length */
export function multicast<T>(this: Observable<T>, subjectOrSubjectFactory: FactoryOrValue<Subject<T>>): ConnectableObservable<T>;
export function multicast<T>(SubjectFactory: (this: Observable<T>) => Subject<T>, selector?: MonoTypeOperatorFunction<T>): Observable<T>;
export function multicast<T, R>(SubjectFactory: (this: Observable<T>) => Subject<T>, selector?: OperatorFunction<T, R>): Observable<R>;
/* tslint:enable:max-line-length */

/**
Expand Down Expand Up @@ -103,7 +104,7 @@ export function multicast<T>(SubjectFactory: (this: Observable<T>) => Subject<T>
* @method multicast
* @owner Observable
*/
export function multicast<T>(this: Observable<T>, subjectOrSubjectFactory: Subject<T> | (() => Subject<T>),
selector?: (source: Observable<T>) => Observable<T>): Observable<T> | ConnectableObservable<T> {
export function multicast<T, R>(this: Observable<T>, subjectOrSubjectFactory: Subject<T> | (() => Subject<T>),
selector?: (source: Observable<T>) => Observable<R>): Observable<R> | ConnectableObservable<R> {
return higherOrder(<any>subjectOrSubjectFactory, selector)(this);
}
5 changes: 3 additions & 2 deletions src/operator/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { publish as higherOrder } from '../operators/publish';

/* tslint:disable:max-line-length */
export function publish<T>(this: Observable<T>): ConnectableObservable<T>;
export function publish<T>(this: Observable<T>, selector: selector<T>): Observable<T>;
export function publish<T>(this: Observable<T>, selector: (source: Observable<T>) => Observable<T>): Observable<T>;
export function publish<T, R>(this: Observable<T>, selector: (source: Observable<T>) => Observable<R>): Observable<R>;
/* tslint:enable:max-line-length */

/**
Expand All @@ -21,7 +22,7 @@ export function publish<T>(this: Observable<T>, selector: selector<T>): Observab
* @method publish
* @owner Observable
*/
export function publish<T>(this: Observable<T>, selector?: (source: Observable<T>) => Observable<T>): Observable<T> | ConnectableObservable<T> {
export function publish<T, R>(this: Observable<T>, selector?: (source: Observable<T>) => Observable<R>): Observable<R> | ConnectableObservable<R> {
return higherOrder(selector)(this);
}

Expand Down
17 changes: 9 additions & 8 deletions src/operators/multicast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { Operator } from '../Operator';
import { Subscriber } from '../Subscriber';
import { Observable } from '../Observable';
import { ConnectableObservable, connectableObservableDescriptor } from '../observable/ConnectableObservable';
import { FactoryOrValue, MonoTypeOperatorFunction } from '../interfaces';
import { FactoryOrValue, MonoTypeOperatorFunction, OperatorFunction } from '../interfaces';

/* tslint:disable:max-line-length */
export function multicast<T>(subjectOrSubjectFactory: FactoryOrValue<Subject<T>>): MonoTypeOperatorFunction<T>;
export function multicast<T>(SubjectFactory: (this: Observable<T>) => Subject<T>, selector?: MonoTypeOperatorFunction<T>): MonoTypeOperatorFunction<T>;
export function multicast<T, R>(SubjectFactory: (this: Observable<T>) => Subject<T>, selector?: OperatorFunction<T, R>): OperatorFunction<T, R>;
/* tslint:enable:max-line-length */

/**
Expand All @@ -29,9 +30,9 @@ export function multicast<T>(SubjectFactory: (this: Observable<T>) => Subject<T>
* @method multicast
* @owner Observable
*/
export function multicast<T>(subjectOrSubjectFactory: Subject<T> | (() => Subject<T>),
selector?: (source: Observable<T>) => Observable<T>): MonoTypeOperatorFunction<T> {
return function multicastOperatorFunction(source: Observable<T>): Observable<T> {
export function multicast<T, R>(subjectOrSubjectFactory: Subject<T> | (() => Subject<T>),
selector?: (source: Observable<T>) => Observable<R>): OperatorFunction<T, R> {
return function multicastOperatorFunction(source: Observable<T>): Observable<R> {
let subjectFactory: () => Subject<T>;
if (typeof subjectOrSubjectFactory === 'function') {
subjectFactory = <() => Subject<T>>subjectOrSubjectFactory;
Expand All @@ -49,15 +50,15 @@ export function multicast<T>(subjectOrSubjectFactory: Subject<T> | (() => Subjec
connectable.source = source;
connectable.subjectFactory = subjectFactory;

return <ConnectableObservable<T>> connectable;
return <ConnectableObservable<R>> connectable;
};
}

export class MulticastOperator<T> implements Operator<T, T> {
export class MulticastOperator<T, R> implements Operator<T, R> {
constructor(private subjectFactory: () => Subject<T>,
private selector: (source: Observable<T>) => Observable<T>) {
private selector: (source: Observable<T>) => Observable<R>) {
}
call(subscriber: Subscriber<T>, source: any): any {
call(subscriber: Subscriber<R>, source: any): any {
const { selector } = this;
const subject = this.subjectFactory();
const subscription = selector(subject).subscribe(subscriber);
Expand Down
5 changes: 3 additions & 2 deletions src/operators/publish.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Subject } from '../Subject';
import { multicast } from './multicast';
import { MonoTypeOperatorFunction } from '../interfaces';
import { MonoTypeOperatorFunction, OperatorFunction } from '../interfaces';

/* tslint:disable:max-line-length */
export function publish<T>(): MonoTypeOperatorFunction<T>;
export function publish<T>(selector: MonoTypeOperatorFunction<T>): MonoTypeOperatorFunction<T>;
export function publish<T, R>(selector: OperatorFunction<T, R>): OperatorFunction<T, R>;
/* tslint:enable:max-line-length */

/**
Expand All @@ -20,7 +21,7 @@ export function publish<T>(selector: MonoTypeOperatorFunction<T>): MonoTypeOpera
* @method publish
* @owner Observable
*/
export function publish<T>(selector?: MonoTypeOperatorFunction<T>): MonoTypeOperatorFunction<T> {
export function publish<T, R>(selector?: any): any {
return selector ?
multicast(() => new Subject<T>(), selector) :
multicast(new Subject<T>());
Expand Down

0 comments on commit 2d58972

Please sign in to comment.