Files
react-native/Libraries/EventEmitter/NativeEventEmitter.js
T
Daniel SainatiandFacebook GitHub Bot 05418f8fcc codemod objects to interfaces where they appear as supertypes of classes
Summary:
Flow is changing the behavior of object types to no longer be valid supertypes of classes. This replaces object types when they appear as supertypes of classes to be interfaces to avoid errors when this change rolls out.

Changelog: [Internal]

Reviewed By: pieterv

Differential Revision: D27193522

fbshipit-source-id: c3e3fca8a4cacd90770a95b773ff2c659774b9a6
2021-03-23 10:26:19 -07:00

115 lines
3.4 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
import {
type EventSubscription,
type IEventEmitter,
} from '../vendor/emitter/EventEmitter';
import Platform from '../Utilities/Platform';
import RCTDeviceEventEmitter from './RCTDeviceEventEmitter';
import invariant from 'invariant';
type NativeModule = $ReadOnly<
interface {
addListener: (eventType: string) => void,
removeListeners: (count: number) => void,
},
>;
export type {EventSubscription};
/**
* `NativeEventEmitter` is intended for use by Native Modules to emit events to
* JavaScript listeners. If a `NativeModule` is supplied to the constructor, it
* will be notified (via `addListener` and `removeListeners`) when the listener
* count changes to manage "native memory".
*
* Currently, all native events are fired via a global `RCTDeviceEventEmitter`.
* This means event names must be globally unique, and it means that call sites
* can theoretically listen to `RCTDeviceEventEmitter` (although discouraged).
*/
export default class NativeEventEmitter<TEventToArgsMap: {...}>
implements IEventEmitter<TEventToArgsMap> {
_nativeModule: ?NativeModule;
constructor(nativeModule: ?NativeModule) {
if (Platform.OS === 'ios') {
invariant(
nativeModule != null,
'`new NativeEventEmitter()` requires a non-null argument.',
);
this._nativeModule = nativeModule;
}
}
addListener<TEvent: $Keys<TEventToArgsMap>>(
eventType: TEvent,
listener: (...args: $ElementType<TEventToArgsMap, TEvent>) => mixed,
context?: mixed,
): EventSubscription {
this._nativeModule?.addListener(eventType);
let subscription: ?EventSubscription = RCTDeviceEventEmitter.addListener(
eventType,
listener,
context,
);
return {
remove: () => {
if (subscription != null) {
this._nativeModule?.removeListeners(1);
// $FlowFixMe[incompatible-use]
subscription.remove();
subscription = null;
}
},
};
}
/**
* @deprecated Use `remove` on the EventSubscription from `addListener`.
*/
removeListener<TEvent: $Keys<TEventToArgsMap>>(
eventType: TEvent,
listener: (...args: $ElementType<TEventToArgsMap, TEvent>) => mixed,
): void {
this._nativeModule?.removeListeners(1);
// NOTE: This will report a deprecation notice via `console.error`.
// $FlowFixMe[prop-missing] - `removeListener` exists but is deprecated.
RCTDeviceEventEmitter.removeListener(eventType, listener);
}
emit<TEvent: $Keys<TEventToArgsMap>>(
eventType: TEvent,
...args: $ElementType<TEventToArgsMap, TEvent>
): void {
// Generally, `RCTDeviceEventEmitter` is directly invoked. But this is
// included for completeness.
RCTDeviceEventEmitter.emit(eventType, ...args);
}
removeAllListeners<TEvent: $Keys<TEventToArgsMap>>(
eventType?: ?TEvent,
): void {
invariant(
eventType != null,
'`NativeEventEmitter.removeAllListener()` requires a non-null argument.',
);
this._nativeModule?.removeListeners(this.listenerCount(eventType));
RCTDeviceEventEmitter.removeAllListeners(eventType);
}
listenerCount<TEvent: $Keys<TEventToArgsMap>>(eventType: TEvent): number {
return RCTDeviceEventEmitter.listenerCount(eventType);
}
}