diff --git a/Libraries/vendor/emitter/EventEmitter.js b/Libraries/vendor/emitter/EventEmitter.js index a4410884b46f3b..6bd20257222d73 100644 --- a/Libraries/vendor/emitter/EventEmitter.js +++ b/Libraries/vendor/emitter/EventEmitter.js @@ -74,6 +74,11 @@ export default class EventEmitter listener: (...args: $ElementType) => mixed, context: mixed, ): EventSubscription { + if (typeof listener !== 'function') { + throw new TypeError( + 'EventEmitter.addListener(...): 2nd argument must be a function.', + ); + } const registrations = allocate<_, _, TEventToArgsMap[TEvent]>( this._registry, eventType, diff --git a/Libraries/vendor/emitter/__tests__/EventEmitter-test.js b/Libraries/vendor/emitter/__tests__/EventEmitter-test.js index 99288ac3e2e88e..34ae1caebfee54 100644 --- a/Libraries/vendor/emitter/__tests__/EventEmitter-test.js +++ b/Libraries/vendor/emitter/__tests__/EventEmitter-test.js @@ -98,6 +98,39 @@ describe('listeners', () => { emitter.emit('A'); expect(listener).toHaveBeenCalledTimes(3); }); + + it('throws on non-function listeners', () => { + const emitter = new EventEmitter<{A: []}>(); + + expect(() => { + emitter.addListener('A', () => {}); + }).not.toThrow(); + + expect(() => { + // $FlowExpectedError + emitter.addListener('A', null); + }).toThrow(); + + expect(() => { + // $FlowExpectedError + emitter.addListener('A', undefined); + }).toThrow(); + + expect(() => { + // $FlowExpectedError + emitter.addListener('A', 'abc'); + }).toThrow(); + + expect(() => { + // $FlowExpectedError + emitter.addListener('A', 123); + }).toThrow(); + + expect(() => { + // $FlowExpectedError + emitter.addListener('A', 123); + }).toThrow(); + }); }); describe('arguments and context', () => { @@ -122,17 +155,15 @@ describe('arguments and context', () => { const emitter = new EventEmitter<{A: []}>(); const context = {}; - let result; - /* $FlowFixMe[missing-this-annot] The 'this' type annotation(s) required by - * Flow's LTI update could not be added via codemod */ - const listener = jest.fn(function () { - result = this; + let that; + const listener = jest.fn(function (this: mixed) { + that = this; }); emitter.addListener('A', listener, context); emitter.emit('A'); expect(listener).toHaveBeenCalled(); - expect(result).toBe(context); + expect(that).toBe(context); }); });