Skip to content

Commit a9904bf

Browse files
committed
fix(fromEvent): allow fromEvent to handle symbols as event names
Allow passing a value of type `symbol` to `eventName` if a `NodeStyleEventEmitter` is passed to `source`, according to [the documentation](https://nodejs.org/api/events.html#emitteraddlistenereventname-listener). Closes #7338
1 parent 0bd47ea commit a9904bf

File tree

3 files changed

+55
-6
lines changed

3 files changed

+55
-6
lines changed

packages/rxjs/spec-dtslint/observables/fromEvent-spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ it('should support a node-style source', () => {
5656
const b = fromEvent<B>(nodeStyleSource, "exit"); // $ExpectType Observable<B>
5757
});
5858

59+
it('should support a node-style source and symbol eventName', () => {
60+
const SYMBOL_EVENT = Symbol();
61+
const source: NodeStyleEventEmitter = nodeStyleSource;
62+
const a = fromEvent(nodeStyleSource, SYMBOL_EVENT); // $ExpectType Observable<unknown>
63+
const b = fromEvent<B>(nodeStyleSource, SYMBOL_EVENT); // $ExpectType Observable<B>
64+
});
65+
5966
it('should deprecate explicit type parameters for a node-style source', () => {
6067
const source: NodeStyleEventEmitter = nodeStyleSource;
6168
const a = fromEvent(nodeStyleSource, "exit"); // $ExpectNoDeprecation

packages/rxjs/spec/observables/fromEvent-spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,39 @@ describe('fromEvent', () => {
121121
expect(offHandler).to.equal(onHandler);
122122
});
123123

124+
it('should pass symbol to "addListener" and "removeListener"', () => {
125+
let onEventName;
126+
let onHandler;
127+
let offEventName;
128+
let offHandler;
129+
130+
const SYMBOL_EVENT = Symbol();
131+
132+
const obj = {
133+
addListener(a: string | symbol, b: (...args: any[]) => void) {
134+
onEventName = a;
135+
onHandler = b;
136+
return this;
137+
},
138+
removeListener(a: string | symbol, b: (...args: any[]) => void) {
139+
offEventName = a;
140+
offHandler = b;
141+
return this;
142+
},
143+
};
144+
145+
const subscription = fromEvent(obj, SYMBOL_EVENT).subscribe(() => {
146+
//noop
147+
});
148+
149+
subscription.unsubscribe();
150+
151+
expect(onEventName).to.equal(SYMBOL_EVENT);
152+
expect(typeof onHandler).to.equal('function');
153+
expect(offEventName).to.equal(onEventName);
154+
expect(offHandler).to.equal(onHandler);
155+
});
156+
124157
it('should setup an event observable on objects with "addListener" and "removeListener" returning nothing', () => {
125158
let onEventName;
126159
let onHandler;

packages/rxjs/src/internal/observable/fromEvent.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,15 @@ export function fromEvent<T, R>(
7777
resultSelector: (event: T) => R
7878
): Observable<R>;
7979

80-
export function fromEvent(target: NodeStyleEventEmitter | ArrayLike<NodeStyleEventEmitter>, eventName: string): Observable<unknown>;
80+
export function fromEvent(
81+
target: NodeStyleEventEmitter | ArrayLike<NodeStyleEventEmitter>,
82+
eventName: string | symbol
83+
): Observable<unknown>;
8184
/** @deprecated Do not specify explicit type parameters. Signatures with type parameters that cannot be inferred will be removed in v8. */
82-
export function fromEvent<T>(target: NodeStyleEventEmitter | ArrayLike<NodeStyleEventEmitter>, eventName: string): Observable<T>;
85+
export function fromEvent<T>(target: NodeStyleEventEmitter | ArrayLike<NodeStyleEventEmitter>, eventName: string | symbol): Observable<T>;
8386
export function fromEvent<R>(
8487
target: NodeStyleEventEmitter | ArrayLike<NodeStyleEventEmitter>,
85-
eventName: string,
88+
eventName: string | symbol,
8689
resultSelector: (...args: any[]) => R
8790
): Observable<R>;
8891

@@ -238,7 +241,7 @@ export function fromEvent<T, R>(
238241
*/
239242
export function fromEvent<T>(
240243
target: any,
241-
eventName: string,
244+
eventName: string | symbol,
242245
options?: EventListenerOptions | ((...args: any[]) => T),
243246
resultSelector?: (...args: any[]) => T
244247
): Observable<T> {
@@ -248,7 +251,7 @@ export function fromEvent<T>(
248251
}
249252

250253
if (resultSelector) {
251-
return fromEvent<T>(target, eventName, options as EventListenerOptions).pipe(mapOneOrManyArgs(resultSelector));
254+
return fromEvent<T>(target, eventName as string, options as EventListenerOptions).pipe(mapOneOrManyArgs(resultSelector));
252255
}
253256

254257
const isValidTarget = isNodeStyleEventEmitter(target) || isJQueryStyleEventEmitter(target) || isEventTarget(target);
@@ -274,7 +277,13 @@ export function fromEvent<T>(
274277
});
275278
}
276279

277-
function doSubscribe(handler: (...args: any[]) => void, subscriber: Subscriber<any>, subTarget: any, eventName: string, options: any) {
280+
function doSubscribe(
281+
handler: (...args: any[]) => void,
282+
subscriber: Subscriber<any>,
283+
subTarget: any,
284+
eventName: string | symbol,
285+
options: any
286+
) {
278287
const [addMethod, removeMethod] = getRegistryMethodNames(subTarget);
279288
if (!addMethod || !removeMethod) {
280289
throw new TypeError('Invalid event target');

0 commit comments

Comments
 (0)