Skip to content

Commit bc34fff

Browse files
committed
fix(publish): fix selector typings
Fixes the typings for publish and multicast, so that selectors that change the observable's type are supported. Closes #2889
1 parent c7c337e commit bc34fff

File tree

6 files changed

+66
-16
lines changed

6 files changed

+66
-16
lines changed

spec/operators/multicast-spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as Rx from '../../dist/package/Rx';
33
import marbleTestingSignature = require('../helpers/marble-testing'); // tslint:disable-line:no-require-imports
44

55
declare const { asDiagram, time, rxTestScheduler };
6+
declare const type;
67
declare const hot: typeof marbleTestingSignature.hot;
78
declare const cold: typeof marbleTestingSignature.cold;
89
declare const expectObservable: typeof marbleTestingSignature.expectObservable;
@@ -638,4 +639,27 @@ describe('Observable.prototype.multicast', () => {
638639
});
639640
});
640641
});
642+
643+
describe('typings', () => {
644+
type('should infer the type', () => {
645+
/* tslint:disable:no-unused-variable */
646+
const source = Rx.Observable.of<number>(1, 2, 3);
647+
const result: Rx.Observable<number> = source.multicast(() => new Subject<number>());
648+
/* tslint:enable:no-unused-variable */
649+
});
650+
651+
type('should infer the type with a selector', () => {
652+
/* tslint:disable:no-unused-variable */
653+
const source = Rx.Observable.of<number>(1, 2, 3);
654+
const result: Rx.Observable<number> = source.multicast(() => new Subject<number>(), s => s.map(x => x));
655+
/* tslint:enable:no-unused-variable */
656+
});
657+
658+
type('should infer the type with a type-changing selector', () => {
659+
/* tslint:disable:no-unused-variable */
660+
const source = Rx.Observable.of<number>(1, 2, 3);
661+
const result: Rx.Observable<string> = source.multicast(() => new Subject<number>(), s => s.map(x => x + '!'));
662+
/* tslint:enable:no-unused-variable */
663+
});
664+
});
641665
});

spec/operators/publish-spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as Rx from '../../dist/package/Rx';
33
import marbleTestingSignature = require('../helpers/marble-testing'); // tslint:disable-line:no-require-imports
44

55
declare const { asDiagram };
6+
declare const type;
67
declare const hot: typeof marbleTestingSignature.hot;
78
declare const cold: typeof marbleTestingSignature.cold;
89
declare const expectObservable: typeof marbleTestingSignature.expectObservable;
@@ -332,4 +333,25 @@ describe('Observable.prototype.publish', () => {
332333
expect(subscriptions).to.equal(1);
333334
done();
334335
});
336+
337+
type('should infer the type', () => {
338+
/* tslint:disable:no-unused-variable */
339+
const source = Rx.Observable.of<number>(1, 2, 3);
340+
const result: Rx.Observable<number> = source.publish();
341+
/* tslint:enable:no-unused-variable */
342+
});
343+
344+
type('should infer the type with a selector', () => {
345+
/* tslint:disable:no-unused-variable */
346+
const source = Rx.Observable.of<number>(1, 2, 3);
347+
const result: Rx.Observable<number> = source.publish(s => s.map(x => x));
348+
/* tslint:enable:no-unused-variable */
349+
});
350+
351+
type('should infer the type with a type-changing selector', () => {
352+
/* tslint:disable:no-unused-variable */
353+
const source = Rx.Observable.of<number>(1, 2, 3);
354+
const result: Rx.Observable<string> = source.publish(s => s.map(x => x + '!'));
355+
/* tslint:enable:no-unused-variable */
356+
});
335357
});

src/operator/multicast.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { Subject } from '../Subject';
22
import { Observable } from '../Observable';
33
import { ConnectableObservable } from '../observable/ConnectableObservable';
44
import { multicast as higherOrder } from '../operators/multicast';
5-
import { FactoryOrValue, MonoTypeOperatorFunction } from '../interfaces';
5+
import { FactoryOrValue, MonoTypeOperatorFunction, OperatorFunction } from '../interfaces';
66

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

1213
/**
@@ -103,7 +104,7 @@ export function multicast<T>(SubjectFactory: (this: Observable<T>) => Subject<T>
103104
* @method multicast
104105
* @owner Observable
105106
*/
106-
export function multicast<T>(this: Observable<T>, subjectOrSubjectFactory: Subject<T> | (() => Subject<T>),
107-
selector?: (source: Observable<T>) => Observable<T>): Observable<T> | ConnectableObservable<T> {
107+
export function multicast<T, R>(this: Observable<T>, subjectOrSubjectFactory: Subject<T> | (() => Subject<T>),
108+
selector?: (source: Observable<T>) => Observable<R>): Observable<R> | ConnectableObservable<R> {
108109
return higherOrder(<any>subjectOrSubjectFactory, selector)(this);
109110
}

src/operator/publish.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { publish as higherOrder } from '../operators/publish';
55

66
/* tslint:disable:max-line-length */
77
export function publish<T>(this: Observable<T>): ConnectableObservable<T>;
8-
export function publish<T>(this: Observable<T>, selector: selector<T>): Observable<T>;
8+
export function publish<T>(this: Observable<T>, selector: (source: Observable<T>) => Observable<T>): Observable<T>;
9+
export function publish<T, R>(this: Observable<T>, selector: (source: Observable<T>) => Observable<R>): Observable<R>;
910
/* tslint:enable:max-line-length */
1011

1112
/**
@@ -21,7 +22,7 @@ export function publish<T>(this: Observable<T>, selector: selector<T>): Observab
2122
* @method publish
2223
* @owner Observable
2324
*/
24-
export function publish<T>(this: Observable<T>, selector?: (source: Observable<T>) => Observable<T>): Observable<T> | ConnectableObservable<T> {
25+
export function publish<T, R>(this: Observable<T>, selector?: (source: Observable<T>) => Observable<R>): Observable<R> | ConnectableObservable<R> {
2526
return higherOrder(selector)(this);
2627
}
2728

src/operators/multicast.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import { Operator } from '../Operator';
33
import { Subscriber } from '../Subscriber';
44
import { Observable } from '../Observable';
55
import { ConnectableObservable, connectableObservableDescriptor } from '../observable/ConnectableObservable';
6-
import { FactoryOrValue, MonoTypeOperatorFunction } from '../interfaces';
6+
import { FactoryOrValue, MonoTypeOperatorFunction, OperatorFunction } from '../interfaces';
77

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

1314
/**
@@ -29,9 +30,9 @@ export function multicast<T>(SubjectFactory: (this: Observable<T>) => Subject<T>
2930
* @method multicast
3031
* @owner Observable
3132
*/
32-
export function multicast<T>(subjectOrSubjectFactory: Subject<T> | (() => Subject<T>),
33-
selector?: (source: Observable<T>) => Observable<T>): MonoTypeOperatorFunction<T> {
34-
return function multicastOperatorFunction(source: Observable<T>): Observable<T> {
33+
export function multicast<T, R>(subjectOrSubjectFactory: Subject<T> | (() => Subject<T>),
34+
selector?: (source: Observable<T>) => Observable<R>): OperatorFunction<T, R> {
35+
return function multicastOperatorFunction(source: Observable<T>): Observable<R> {
3536
let subjectFactory: () => Subject<T>;
3637
if (typeof subjectOrSubjectFactory === 'function') {
3738
subjectFactory = <() => Subject<T>>subjectOrSubjectFactory;
@@ -49,15 +50,15 @@ export function multicast<T>(subjectOrSubjectFactory: Subject<T> | (() => Subjec
4950
connectable.source = source;
5051
connectable.subjectFactory = subjectFactory;
5152

52-
return <ConnectableObservable<T>> connectable;
53+
return <ConnectableObservable<R>> connectable;
5354
};
5455
}
5556

56-
export class MulticastOperator<T> implements Operator<T, T> {
57+
export class MulticastOperator<T, R> implements Operator<T, R> {
5758
constructor(private subjectFactory: () => Subject<T>,
58-
private selector: (source: Observable<T>) => Observable<T>) {
59+
private selector: (source: Observable<T>) => Observable<R>) {
5960
}
60-
call(subscriber: Subscriber<T>, source: any): any {
61+
call(subscriber: Subscriber<R>, source: any): any {
6162
const { selector } = this;
6263
const subject = this.subjectFactory();
6364
const subscription = selector(subject).subscribe(subscriber);

src/operators/publish.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Subject } from '../Subject';
22
import { multicast } from './multicast';
3-
import { MonoTypeOperatorFunction } from '../interfaces';
3+
import { MonoTypeOperatorFunction, OperatorFunction } from '../interfaces';
44

55
/* tslint:disable:max-line-length */
66
export function publish<T>(): MonoTypeOperatorFunction<T>;
77
export function publish<T>(selector: MonoTypeOperatorFunction<T>): MonoTypeOperatorFunction<T>;
8+
export function publish<T, R>(selector: OperatorFunction<T, R>): OperatorFunction<T, R>;
89
/* tslint:enable:max-line-length */
910

1011
/**
@@ -20,8 +21,8 @@ export function publish<T>(selector: MonoTypeOperatorFunction<T>): MonoTypeOpera
2021
* @method publish
2122
* @owner Observable
2223
*/
23-
export function publish<T>(selector?: MonoTypeOperatorFunction<T>): MonoTypeOperatorFunction<T> {
24+
export function publish<T, R>(selector?: OperatorFunction<T, R>): OperatorFunction<T, R> {
2425
return selector ?
2526
multicast(() => new Subject<T>(), selector) :
26-
multicast(new Subject<T>());
27+
multicast(new Subject<T>()) as OperatorFunction<T, any>;
2728
}

0 commit comments

Comments
 (0)