From fff62e603bdc6f71072fce9645712d306e292c2a Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 31 Jan 2025 04:38:13 -0800 Subject: [PATCH 1/3] Align EventEmitter definitions with TypeScript Summary: Changelog: [Internal] Differential Revision: D68953500 --- .../EventEmitter/NativeEventEmitter.js | 10 +++++-- .../__mocks__/NativeEventEmitter.js | 5 ++-- .../Libraries/vendor/emitter/EventEmitter.js | 30 +++++++++++++------ scripts/build/build-types.js | 1 + 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/packages/react-native/Libraries/EventEmitter/NativeEventEmitter.js b/packages/react-native/Libraries/EventEmitter/NativeEventEmitter.js index f30a69df7a4f43..28b19aaf607dd1 100644 --- a/packages/react-native/Libraries/EventEmitter/NativeEventEmitter.js +++ b/packages/react-native/Libraries/EventEmitter/NativeEventEmitter.js @@ -26,6 +26,9 @@ interface NativeModule { export type {EventSubscription}; +// $FlowFixMe[unclear-type] unclear type of events +type UnsafeObject = Object; + /** * `NativeEventEmitter` is intended for use by Native Modules to emit events to * JavaScript listeners. If a `NativeModule` is supplied to the constructor, it @@ -36,8 +39,11 @@ export type {EventSubscription}; * 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 - implements IEventEmitter +export default class NativeEventEmitter< + TEventToArgsMap: $ReadOnly< + Record>, + > = $ReadOnly>>, +> implements IEventEmitter { _nativeModule: ?NativeModule; diff --git a/packages/react-native/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js b/packages/react-native/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js index 1a63d5a88a44ac..1b6196cb93fc80 100644 --- a/packages/react-native/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js +++ b/packages/react-native/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js @@ -18,8 +18,9 @@ import RCTDeviceEventEmitter from '../RCTDeviceEventEmitter'; /** * Mock `NativeEventEmitter` to ignore Native Modules. */ -export default class NativeEventEmitter - implements IEventEmitter +export default class NativeEventEmitter< + TEventToArgsMap: $ReadOnly>>, +> implements IEventEmitter { addListener>( eventType: TEvent, diff --git a/packages/react-native/Libraries/vendor/emitter/EventEmitter.js b/packages/react-native/Libraries/vendor/emitter/EventEmitter.js index 1087654ea57827..016bff45a41b3f 100644 --- a/packages/react-native/Libraries/vendor/emitter/EventEmitter.js +++ b/packages/react-native/Libraries/vendor/emitter/EventEmitter.js @@ -8,11 +8,16 @@ * @format */ +// $FlowFixMe[unclear-type] unclear type of events +type UnsafeObject = Object; + export interface EventSubscription { remove(): void; } -export interface IEventEmitter { +export interface IEventEmitter< + TEventToArgsMap: $ReadOnly>>, +> { addListener>( eventType: TEvent, listener: (...args: TEventToArgsMap[TEvent]) => mixed, @@ -35,7 +40,9 @@ interface Registration { +remove: () => void; } -type Registry = { +type Registry< + TEventToArgsMap: $ReadOnly>>, +> = { [K in keyof TEventToArgsMap]: Set>, }; @@ -59,8 +66,11 @@ type Registry = { * emitter.emit('error', new Error('Resource not found')); * */ -export default class EventEmitter - implements IEventEmitter +export default class EventEmitter< + TEventToArgsMap: $ReadOnly< + Record>, + > = $ReadOnly>>, +> implements IEventEmitter { // $FlowFixMe[incompatible-type] #registry: Registry = {}; @@ -81,7 +91,7 @@ export default class EventEmitter } const registrations = allocate< TEventToArgsMap, - TEvent, + $Keys, TEventToArgsMap[TEvent], >(this.#registry, eventType); const registration: Registration = { @@ -136,20 +146,22 @@ export default class EventEmitter * Returns the number of registered listeners for the supplied event. */ listenerCount>(eventType: TEvent): number { - const registrations: ?Set> = this.#registry[eventType]; + const registrations: ?Set> = + this.#registry[eventType]; return registrations == null ? 0 : registrations.size; } } function allocate< - TEventToArgsMap: {...}, + TEventToArgsMap: $ReadOnly>>, TEvent: $Keys, TEventArgs: TEventToArgsMap[TEvent], >( registry: Registry, eventType: TEvent, -): Set> { - let registrations: ?Set> = registry[eventType]; +): Set> { + let registrations: ?Set> = + registry[eventType]; if (registrations == null) { registrations = new Set(); registry[eventType] = registrations; diff --git a/scripts/build/build-types.js b/scripts/build/build-types.js index 495079ddd1073f..70c455c911de30 100644 --- a/scripts/build/build-types.js +++ b/scripts/build/build-types.js @@ -24,6 +24,7 @@ const IGNORE_PATTERN = '**/__{tests,mocks,fixtures}__/**'; const SOURCE_PATTERNS = [ // Start with Animated only path.join(PACKAGES_DIR, 'react-native/Libraries/Alert/**/*.js'), + path.join(PACKAGES_DIR, 'react-native/Libraries/vendor/**/*.js'), path.join(PACKAGES_DIR, 'react-native/Libraries/TurboModule/RCTExport.js'), path.join(PACKAGES_DIR, 'react-native/Libraries/Types/RootTagTypes.js'), path.join(PACKAGES_DIR, 'react-native/Libraries/ReactNative/RootTag.js'), From 128afad12c17ee3066d1b1f97f4528e447b754f7 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 31 Jan 2025 04:38:13 -0800 Subject: [PATCH 2/3] Rename EventSubscription to EmitterSubscription to align with OSS types Summary: Changelog: [Internal] Differential Revision: D68953498 --- .../Libraries/Animated/nodes/AnimatedValue.js | 6 +++--- .../Libraries/Animated/useAnimatedProps.js | 4 ++-- packages/react-native/Libraries/AppState/AppState.js | 4 ++-- .../Libraries/BugReporting/BugReporting.js | 6 +++--- .../Components/AccessibilityInfo/AccessibilityInfo.js | 4 ++-- .../Libraries/Components/Keyboard/Keyboard.js | 4 ++-- .../Components/Keyboard/KeyboardAvoidingView.js | 4 ++-- .../Libraries/Components/ScrollView/ScrollView.js | 10 +++++----- .../Libraries/EventEmitter/NativeEventEmitter.js | 8 ++++---- .../EventEmitter/__mocks__/NativeEventEmitter.js | 4 ++-- .../Libraries/Interaction/InteractionManagerStub.js | 4 ++-- packages/react-native/Libraries/Linking/Linking.js | 4 ++-- packages/react-native/Libraries/Modal/Modal.js | 4 ++-- .../Libraries/Network/RCTNetworking.android.js | 4 ++-- .../Libraries/Network/RCTNetworking.ios.js | 4 ++-- .../Libraries/Network/RCTNetworking.js.flow | 4 ++-- .../Libraries/Network/XMLHttpRequest_new.js | 4 ++-- .../Libraries/Network/XMLHttpRequest_old.js | 4 ++-- .../PushNotificationIOS/PushNotificationIOS.js | 4 ++-- packages/react-native/Libraries/Types/CodegenTypes.js | 4 ++-- .../react-native/Libraries/Utilities/Appearance.js | 6 +++--- .../react-native/Libraries/Utilities/DevSettings.js | 4 ++-- .../react-native/Libraries/Utilities/Dimensions.js | 4 ++-- .../react-native/Libraries/WebSocket/WebSocket_new.js | 4 ++-- .../react-native/Libraries/WebSocket/WebSocket_old.js | 4 ++-- .../Libraries/vendor/emitter/EventEmitter.js | 6 +++--- .../vendor/emitter/__tests__/EventEmitter-test.js | 4 ++-- .../src/private/animated/NativeAnimatedHelper.js | 6 +++--- .../js/examples/Accessibility/AccessibilityExample.js | 4 ++-- .../TurboModule/NativeCxxModuleExampleExample.js | 4 ++-- .../examples/TurboModule/SampleTurboModuleExample.js | 4 ++-- 31 files changed, 72 insertions(+), 72 deletions(-) diff --git a/packages/react-native/Libraries/Animated/nodes/AnimatedValue.js b/packages/react-native/Libraries/Animated/nodes/AnimatedValue.js index 44122d9fe5bcc0..c0c432037ec77e 100644 --- a/packages/react-native/Libraries/Animated/nodes/AnimatedValue.js +++ b/packages/react-native/Libraries/Animated/nodes/AnimatedValue.js @@ -8,7 +8,7 @@ * @format */ -import type {EventSubscription} from '../../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../../vendor/emitter/EventEmitter'; import type {PlatformConfig} from '../AnimatedPlatformConfig'; import type Animation, {EndCallback} from '../animations/Animation'; import type {InterpolationConfigType} from './AnimatedInterpolation'; @@ -86,7 +86,7 @@ function _executeAsAnimatedBatch(id: string, operation: () => void) { */ export default class AnimatedValue extends AnimatedWithChildren { #listenerCount: number = 0; - #updateSubscription: ?EventSubscription = null; + #updateSubscription: ?EmitterSubscription = null; _value: number; _startingValue: number; @@ -159,7 +159,7 @@ export default class AnimatedValue extends AnimatedWithChildren { } const nativeTag = this.__getNativeTag(); NativeAnimatedAPI.startListeningToAnimatedNodeValue(nativeTag); - const subscription: EventSubscription = + const subscription: EmitterSubscription = NativeAnimatedHelper.nativeEventEmitter.addListener( 'onAnimatedValueUpdate', data => { diff --git a/packages/react-native/Libraries/Animated/useAnimatedProps.js b/packages/react-native/Libraries/Animated/useAnimatedProps.js index 4bf3cabeb26c99..49c3ce8d272d67 100644 --- a/packages/react-native/Libraries/Animated/useAnimatedProps.js +++ b/packages/react-native/Libraries/Animated/useAnimatedProps.js @@ -8,7 +8,7 @@ * @format */ -import type {EventSubscription} from '../EventEmitter/NativeEventEmitter'; +import type {EmitterSubscription} from '../EventEmitter/NativeEventEmitter'; import type {AnimatedPropsAllowlist} from './nodes/AnimatedProps'; import NativeAnimatedHelper from '../../src/private/animated/NativeAnimatedHelper'; @@ -67,7 +67,7 @@ export default function useAnimatedProps( // If multiple components call `flushQueue`, the first one will flush the // queue and subsequent ones will do nothing. NativeAnimatedHelper.API.flushQueue(); - let drivenAnimationEndedListener: ?EventSubscription = null; + let drivenAnimationEndedListener: ?EmitterSubscription = null; if (node.__isNative) { drivenAnimationEndedListener = NativeAnimatedHelper.nativeEventEmitter.addListener( diff --git a/packages/react-native/Libraries/AppState/AppState.js b/packages/react-native/Libraries/AppState/AppState.js index c7df0d1b1e048c..fe0bf1fa53b1c3 100644 --- a/packages/react-native/Libraries/AppState/AppState.js +++ b/packages/react-native/Libraries/AppState/AppState.js @@ -11,7 +11,7 @@ import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; import logError from '../Utilities/logError'; import Platform from '../Utilities/Platform'; -import {type EventSubscription} from '../vendor/emitter/EventEmitter'; +import {type EmitterSubscription} from '../vendor/emitter/EventEmitter'; import NativeAppState from './NativeAppState'; export type AppStateValues = 'inactive' | 'background' | 'active'; @@ -92,7 +92,7 @@ class AppState { addEventListener>( type: K, handler: (...$ElementType) => void, - ): EventSubscription { + ): EmitterSubscription { const emitter = this._emitter; if (emitter == null) { throw new Error('Cannot use AppState when `isAvailable` is false.'); diff --git a/packages/react-native/Libraries/BugReporting/BugReporting.js b/packages/react-native/Libraries/BugReporting/BugReporting.js index a11ad8084840b7..e94911df503a46 100644 --- a/packages/react-native/Libraries/BugReporting/BugReporting.js +++ b/packages/react-native/Libraries/BugReporting/BugReporting.js @@ -10,7 +10,7 @@ import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter'; import NativeRedBox from '../NativeModules/specs/NativeRedBox'; -import {type EventSubscription} from '../vendor/emitter/EventEmitter'; +import {type EmitterSubscription} from '../vendor/emitter/EventEmitter'; import NativeBugReporting from './NativeBugReporting'; type ExtraData = {[key: string]: string, ...}; @@ -36,8 +36,8 @@ function defaultExtras() { class BugReporting { static _extraSources: Map = new Map(); static _fileSources: Map = new Map(); - static _subscription: ?EventSubscription = null; - static _redboxSubscription: ?EventSubscription = null; + static _subscription: ?EmitterSubscription = null; + static _redboxSubscription: ?EmitterSubscription = null; static _maybeInit() { if (!BugReporting._subscription) { diff --git a/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js b/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js index ccae5960ac2106..4ce18080a15fef 100644 --- a/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js +++ b/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js @@ -9,7 +9,7 @@ */ import type {HostInstance} from '../../Renderer/shims/ReactNativeTypes'; -import type {EventSubscription} from '../../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../../vendor/emitter/EventEmitter'; import RCTDeviceEventEmitter from '../../EventEmitter/RCTDeviceEventEmitter'; import {sendAccessibilityEvent} from '../../ReactNative/RendererProxy'; @@ -398,7 +398,7 @@ const AccessibilityInfo = { eventName: K, // $FlowIssue[incompatible-type] - Flow bug with unions and generics (T128099423) handler: (...$ElementType) => void, - ): EventSubscription { + ): EmitterSubscription { const deviceEventName = EventNames.get(eventName); return deviceEventName == null ? {remove(): void {}} diff --git a/packages/react-native/Libraries/Components/Keyboard/Keyboard.js b/packages/react-native/Libraries/Components/Keyboard/Keyboard.js index 1bf9a591affdff..cde58ce1e2ab7c 100644 --- a/packages/react-native/Libraries/Components/Keyboard/Keyboard.js +++ b/packages/react-native/Libraries/Components/Keyboard/Keyboard.js @@ -8,7 +8,7 @@ * @flow strict-local */ -import type {EventSubscription} from '../../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../../vendor/emitter/EventEmitter'; import NativeEventEmitter from '../../EventEmitter/NativeEventEmitter'; import LayoutAnimation from '../../LayoutAnimation/LayoutAnimation'; @@ -150,7 +150,7 @@ class Keyboard { eventType: K, listener: (...$ElementType) => mixed, context?: mixed, - ): EventSubscription { + ): EmitterSubscription { return this._emitter.addListener(eventType, listener); } diff --git a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js index 08fdf276faa524..f32a8e5f08e241 100644 --- a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -19,7 +19,7 @@ import type {KeyboardEvent, KeyboardMetrics} from './Keyboard'; import LayoutAnimation from '../../LayoutAnimation/LayoutAnimation'; import StyleSheet from '../../StyleSheet/StyleSheet'; import Platform from '../../Utilities/Platform'; -import {type EventSubscription} from '../../vendor/emitter/EventEmitter'; +import {type EmitterSubscription} from '../../vendor/emitter/EventEmitter'; import AccessibilityInfo from '../AccessibilityInfo/AccessibilityInfo'; import View from '../View/View'; import Keyboard from './Keyboard'; @@ -62,7 +62,7 @@ type State = { class KeyboardAvoidingView extends React.Component { _frame: ?ViewLayout = null; _keyboardEvent: ?KeyboardEvent = null; - _subscriptions: Array = []; + _subscriptions: Array = []; viewRef: {current: React.ElementRef | null, ...}; _initialFrameHeight: number = 0; _bottom: number = 0; diff --git a/packages/react-native/Libraries/Components/ScrollView/ScrollView.js b/packages/react-native/Libraries/Components/ScrollView/ScrollView.js index d4c973dcd69324..21301865ac5e19 100644 --- a/packages/react-native/Libraries/Components/ScrollView/ScrollView.js +++ b/packages/react-native/Libraries/Components/ScrollView/ScrollView.js @@ -18,7 +18,7 @@ import type { PressEvent, ScrollEvent, } from '../../Types/CoreEventTypes'; -import type {EventSubscription} from '../../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../../vendor/emitter/EventEmitter'; import type {KeyboardEvent, KeyboardMetrics} from '../Keyboard/Keyboard'; import typeof View from '../View/View'; import type {ViewProps} from '../View/ViewPropTypes'; @@ -735,10 +735,10 @@ class ScrollView extends React.Component { _animated: ?boolean = null; - _subscriptionKeyboardWillShow: ?EventSubscription = null; - _subscriptionKeyboardWillHide: ?EventSubscription = null; - _subscriptionKeyboardDidShow: ?EventSubscription = null; - _subscriptionKeyboardDidHide: ?EventSubscription = null; + _subscriptionKeyboardWillShow: ?EmitterSubscription = null; + _subscriptionKeyboardWillHide: ?EmitterSubscription = null; + _subscriptionKeyboardDidShow: ?EmitterSubscription = null; + _subscriptionKeyboardDidHide: ?EmitterSubscription = null; state: State = { layoutHeight: null, diff --git a/packages/react-native/Libraries/EventEmitter/NativeEventEmitter.js b/packages/react-native/Libraries/EventEmitter/NativeEventEmitter.js index 28b19aaf607dd1..48975366760490 100644 --- a/packages/react-native/Libraries/EventEmitter/NativeEventEmitter.js +++ b/packages/react-native/Libraries/EventEmitter/NativeEventEmitter.js @@ -11,7 +11,7 @@ 'use strict'; import type { - EventSubscription, + EmitterSubscription, IEventEmitter, } from '../vendor/emitter/EventEmitter'; @@ -24,7 +24,7 @@ interface NativeModule { removeListeners(count: number): void; } -export type {EventSubscription}; +export type {EmitterSubscription}; // $FlowFixMe[unclear-type] unclear type of events type UnsafeObject = Object; @@ -82,9 +82,9 @@ export default class NativeEventEmitter< eventType: TEvent, listener: (...args: $ElementType) => mixed, context?: mixed, - ): EventSubscription { + ): EmitterSubscription { this._nativeModule?.addListener(eventType); - let subscription: ?EventSubscription = RCTDeviceEventEmitter.addListener( + let subscription: ?EmitterSubscription = RCTDeviceEventEmitter.addListener( eventType, listener, context, diff --git a/packages/react-native/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js b/packages/react-native/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js index 1b6196cb93fc80..f6f24c2a115afc 100644 --- a/packages/react-native/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js +++ b/packages/react-native/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js @@ -9,7 +9,7 @@ */ import type { - EventSubscription, + EmitterSubscription, IEventEmitter, } from '../../vendor/emitter/EventEmitter'; @@ -26,7 +26,7 @@ export default class NativeEventEmitter< eventType: TEvent, listener: (...args: $ElementType) => mixed, context?: mixed, - ): EventSubscription { + ): EmitterSubscription { return RCTDeviceEventEmitter.addListener(eventType, listener, context); } diff --git a/packages/react-native/Libraries/Interaction/InteractionManagerStub.js b/packages/react-native/Libraries/Interaction/InteractionManagerStub.js index 5b45d8bd76b707..92c7588290a3f7 100644 --- a/packages/react-native/Libraries/Interaction/InteractionManagerStub.js +++ b/packages/react-native/Libraries/Interaction/InteractionManagerStub.js @@ -8,7 +8,7 @@ * @format */ -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; const invariant = require('invariant'); @@ -155,7 +155,7 @@ const InteractionManagerStub = { /** * @deprecated */ - addListener(): EventSubscription { + addListener(): EmitterSubscription { return { remove() {}, }; diff --git a/packages/react-native/Libraries/Linking/Linking.js b/packages/react-native/Libraries/Linking/Linking.js index b42b38d322fe35..b71c3fce7db197 100644 --- a/packages/react-native/Libraries/Linking/Linking.js +++ b/packages/react-native/Libraries/Linking/Linking.js @@ -8,7 +8,7 @@ * @flow strict-local */ -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; import Platform from '../Utilities/Platform'; @@ -35,7 +35,7 @@ class LinkingImpl extends NativeEventEmitter { addEventListener>( eventType: K, listener: (...$ElementType) => mixed, - ): EventSubscription { + ): EmitterSubscription { return this.addListener(eventType, listener); } diff --git a/packages/react-native/Libraries/Modal/Modal.js b/packages/react-native/Libraries/Modal/Modal.js index edc24f0ecb6e6f..64b5bf1789ef3d 100644 --- a/packages/react-native/Libraries/Modal/Modal.js +++ b/packages/react-native/Libraries/Modal/Modal.js @@ -13,7 +13,7 @@ import type {RootTag} from '../ReactNative/RootTag'; import type {DirectEventHandler} from '../Types/CodegenTypes'; import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; -import {type EventSubscription} from '../vendor/emitter/EventEmitter'; +import {type EmitterSubscription} from '../vendor/emitter/EventEmitter'; import ModalInjection from './ModalInjection'; import NativeModalManager from './NativeModalManager'; import RCTModalHostView from './RCTModalHostViewNativeComponent'; @@ -210,7 +210,7 @@ class Modal extends React.Component { static contextType: React.Context = RootTagContext; _identifier: number; - _eventSubscription: ?EventSubscription; + _eventSubscription: ?EmitterSubscription; constructor(props: Props) { super(props); diff --git a/packages/react-native/Libraries/Network/RCTNetworking.android.js b/packages/react-native/Libraries/Network/RCTNetworking.android.js index d5d782a21004d4..8e735a48961d14 100644 --- a/packages/react-native/Libraries/Network/RCTNetworking.android.js +++ b/packages/react-native/Libraries/Network/RCTNetworking.android.js @@ -8,7 +8,7 @@ * @flow */ -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; import type {RequestBody} from './convertRequestBody'; import type {RCTNetworkingEventDefinitions} from './RCTNetworkingEventDefinitions.flow'; import type {NativeResponseType} from './XMLHttpRequest'; @@ -52,7 +52,7 @@ const RCTNetworking = { eventType: K, listener: (...$ElementType) => mixed, context?: mixed, - ): EventSubscription { + ): EmitterSubscription { // $FlowFixMe[incompatible-call] return emitter.addListener(eventType, listener, context); }, diff --git a/packages/react-native/Libraries/Network/RCTNetworking.ios.js b/packages/react-native/Libraries/Network/RCTNetworking.ios.js index 4d528eebdba2a7..e7694323aac9bb 100644 --- a/packages/react-native/Libraries/Network/RCTNetworking.ios.js +++ b/packages/react-native/Libraries/Network/RCTNetworking.ios.js @@ -11,7 +11,7 @@ 'use strict'; import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter'; -import {type EventSubscription} from '../vendor/emitter/EventEmitter'; +import {type EmitterSubscription} from '../vendor/emitter/EventEmitter'; import convertRequestBody, {type RequestBody} from './convertRequestBody'; import NativeNetworkingIOS from './NativeNetworkingIOS'; import {type RCTNetworkingEventDefinitions} from './RCTNetworkingEventDefinitions.flow'; @@ -22,7 +22,7 @@ const RCTNetworking = { eventType: K, listener: (...$ElementType) => mixed, context?: mixed, - ): EventSubscription { + ): EmitterSubscription { // $FlowFixMe[incompatible-call] return RCTDeviceEventEmitter.addListener(eventType, listener, context); }, diff --git a/packages/react-native/Libraries/Network/RCTNetworking.js.flow b/packages/react-native/Libraries/Network/RCTNetworking.js.flow index 6f8f64a6e91914..4c3d1a396866ed 100644 --- a/packages/react-native/Libraries/Network/RCTNetworking.js.flow +++ b/packages/react-native/Libraries/Network/RCTNetworking.js.flow @@ -10,7 +10,7 @@ 'use strict'; -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; import type {RequestBody} from './convertRequestBody'; import type {RCTNetworkingEventDefinitions} from './RCTNetworkingEventDefinitions.flow'; import type {NativeResponseType} from './XMLHttpRequest'; @@ -21,7 +21,7 @@ declare const RCTNetworking: interface { // $FlowFixMe[invalid-computed-prop] listener: (...$ElementType) => mixed, context?: mixed, - ): EventSubscription, + ): EmitterSubscription, sendRequest( method: string, diff --git a/packages/react-native/Libraries/Network/XMLHttpRequest_new.js b/packages/react-native/Libraries/Network/XMLHttpRequest_new.js index 1eec800735d4d0..e067889dac805a 100644 --- a/packages/react-native/Libraries/Network/XMLHttpRequest_new.js +++ b/packages/react-native/Libraries/Network/XMLHttpRequest_new.js @@ -24,7 +24,7 @@ import { import EventTarget from '../../src/private/webapis/dom/events/EventTarget'; import {dispatchTrustedEvent} from '../../src/private/webapis/dom/events/internals/EventTargetInternals'; import ProgressEvent from '../../src/private/webapis/xhr/events/ProgressEvent'; -import {type EventSubscription} from '../vendor/emitter/EventEmitter'; +import {type EmitterSubscription} from '../vendor/emitter/EventEmitter'; const BlobManager = require('../Blob/BlobManager').default; const GlobalPerformanceLogger = require('../Utilities/GlobalPerformanceLogger'); @@ -138,7 +138,7 @@ class XMLHttpRequest extends EventTarget { upload: XMLHttpRequestEventTarget = new XMLHttpRequestEventTarget(); _requestId: ?number; - _subscriptions: Array; + _subscriptions: Array; _aborted: boolean = false; _cachedResponse: Response; diff --git a/packages/react-native/Libraries/Network/XMLHttpRequest_old.js b/packages/react-native/Libraries/Network/XMLHttpRequest_old.js index 8797ccb8937da1..53673998fc520e 100644 --- a/packages/react-native/Libraries/Network/XMLHttpRequest_old.js +++ b/packages/react-native/Libraries/Network/XMLHttpRequest_old.js @@ -12,7 +12,7 @@ import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger'; -import {type EventSubscription} from '../vendor/emitter/EventEmitter'; +import {type EmitterSubscription} from '../vendor/emitter/EventEmitter'; import EventTarget from 'event-target-shim'; const BlobManager = require('../Blob/BlobManager').default; @@ -116,7 +116,7 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { upload: XMLHttpRequestEventTarget = new XMLHttpRequestEventTarget(); _requestId: ?number; - _subscriptions: Array; + _subscriptions: Array; _aborted: boolean = false; _cachedResponse: Response; diff --git a/packages/react-native/Libraries/PushNotificationIOS/PushNotificationIOS.js b/packages/react-native/Libraries/PushNotificationIOS/PushNotificationIOS.js index 9453c82b9ab8be..edaaac2fdb025c 100644 --- a/packages/react-native/Libraries/PushNotificationIOS/PushNotificationIOS.js +++ b/packages/react-native/Libraries/PushNotificationIOS/PushNotificationIOS.js @@ -8,7 +8,7 @@ * @flow */ -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; import Platform from '../Utilities/Platform'; @@ -46,7 +46,7 @@ const PushNotificationEmitter = Platform.OS !== 'ios' ? null : NativePushNotificationManagerIOS, ); -const _notifHandlers = new Map(); +const _notifHandlers = new Map(); const DEVICE_NOTIF_EVENT = 'remoteNotificationReceived'; const NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered'; diff --git a/packages/react-native/Libraries/Types/CodegenTypes.js b/packages/react-native/Libraries/Types/CodegenTypes.js index 3313a514f5f750..4c69002382c401 100644 --- a/packages/react-native/Libraries/Types/CodegenTypes.js +++ b/packages/react-native/Libraries/Types/CodegenTypes.js @@ -10,7 +10,7 @@ 'use strict'; -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; import type {SyntheticEvent} from './CoreEventTypes'; // Event types @@ -45,4 +45,4 @@ export type WithDefault = ?Type; export type EventEmitter = ( handler: (T) => void | Promise, -) => EventSubscription; +) => EmitterSubscription; diff --git a/packages/react-native/Libraries/Utilities/Appearance.js b/packages/react-native/Libraries/Utilities/Appearance.js index 6c13f4d6d530c5..1d79bfabcc85a6 100644 --- a/packages/react-native/Libraries/Utilities/Appearance.js +++ b/packages/react-native/Libraries/Utilities/Appearance.js @@ -8,7 +8,7 @@ * @flow strict-local */ -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; import type {AppearancePreferences, ColorSchemeName} from './NativeAppearance'; import typeof INativeAppearance from './NativeAppearance'; @@ -26,7 +26,7 @@ let lazyState: ?{ // NOTE: If `NativeAppearance` is null, this will always be null. appearance: ?Appearance, // NOTE: This is non-nullable to make it easier for `onChangedListener` to - // return a non-nullable `EventSubscription` value. This is not the common + // return a non-nullable `EmitterSubscription` value. This is not the common // path, so we do not have to over-optimize it. +eventEmitter: EventEmitter<{change: [Appearance]}>, }; @@ -108,7 +108,7 @@ export function setColorScheme(colorScheme: ?ColorSchemeName): void { */ export function addChangeListener( listener: ({colorScheme: ?ColorSchemeName}) => void, -): EventSubscription { +): EmitterSubscription { const {eventEmitter} = getState(); return eventEmitter.addListener('change', listener); } diff --git a/packages/react-native/Libraries/Utilities/DevSettings.js b/packages/react-native/Libraries/Utilities/DevSettings.js index af227f2582d539..666e87da3732c5 100644 --- a/packages/react-native/Libraries/Utilities/DevSettings.js +++ b/packages/react-native/Libraries/Utilities/DevSettings.js @@ -8,7 +8,7 @@ * @format */ -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; import NativeDevSettings from '../NativeModules/specs/NativeDevSettings'; @@ -34,7 +34,7 @@ if (__DEV__) { // If you want to use the native module on other platforms, please remove this condition and test its behavior Platform.OS !== 'ios' ? null : NativeDevSettings, ); - const subscriptions = new Map(); + const subscriptions = new Map(); DevSettings = { addMenuItem(title: string, handler: () => mixed): void { diff --git a/packages/react-native/Libraries/Utilities/Dimensions.js b/packages/react-native/Libraries/Utilities/Dimensions.js index e5775a9fc8d921..bfd8be7468c3bd 100644 --- a/packages/react-native/Libraries/Utilities/Dimensions.js +++ b/packages/react-native/Libraries/Utilities/Dimensions.js @@ -10,7 +10,7 @@ import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter'; import EventEmitter, { - type EventSubscription, + type EmitterSubscription, } from '../vendor/emitter/EventEmitter'; import NativeDeviceInfo, { type DimensionsPayload, @@ -101,7 +101,7 @@ class Dimensions { static addEventListener( type: 'change', handler: Function, - ): EventSubscription { + ): EmitterSubscription { invariant( type === 'change', 'Trying to subscribe to unknown event: "%s"', diff --git a/packages/react-native/Libraries/WebSocket/WebSocket_new.js b/packages/react-native/Libraries/WebSocket/WebSocket_new.js index 3062613ab599ac..637ea65589f0cf 100644 --- a/packages/react-native/Libraries/WebSocket/WebSocket_new.js +++ b/packages/react-native/Libraries/WebSocket/WebSocket_new.js @@ -10,7 +10,7 @@ import type {EventCallback} from '../../src/private/webapis/dom/events/EventTarget'; import type {BlobData} from '../Blob/BlobTypes'; -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; import Event from '../../src/private/webapis/dom/events/Event'; import { @@ -86,7 +86,7 @@ class WebSocket extends EventTarget { _socketId: number; _eventEmitter: NativeEventEmitter; - _subscriptions: Array; + _subscriptions: Array; _binaryType: ?BinaryType; bufferedAmount: number; diff --git a/packages/react-native/Libraries/WebSocket/WebSocket_old.js b/packages/react-native/Libraries/WebSocket/WebSocket_old.js index 348161af248b3d..483991db166e80 100644 --- a/packages/react-native/Libraries/WebSocket/WebSocket_old.js +++ b/packages/react-native/Libraries/WebSocket/WebSocket_old.js @@ -9,7 +9,7 @@ */ import type {BlobData} from '../Blob/BlobTypes'; -import type {EventSubscription} from '../vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../vendor/emitter/EventEmitter'; import Blob from '../Blob/Blob'; import BlobManager from '../Blob/BlobManager'; @@ -81,7 +81,7 @@ class WebSocket extends (EventTarget(...WEBSOCKET_EVENTS): typeof EventTarget) { _socketId: number; _eventEmitter: NativeEventEmitter; - _subscriptions: Array; + _subscriptions: Array; _binaryType: ?BinaryType; onclose: ?Function; diff --git a/packages/react-native/Libraries/vendor/emitter/EventEmitter.js b/packages/react-native/Libraries/vendor/emitter/EventEmitter.js index 016bff45a41b3f..b16338605b9b2e 100644 --- a/packages/react-native/Libraries/vendor/emitter/EventEmitter.js +++ b/packages/react-native/Libraries/vendor/emitter/EventEmitter.js @@ -11,7 +11,7 @@ // $FlowFixMe[unclear-type] unclear type of events type UnsafeObject = Object; -export interface EventSubscription { +export interface EmitterSubscription { remove(): void; } @@ -22,7 +22,7 @@ export interface IEventEmitter< eventType: TEvent, listener: (...args: TEventToArgsMap[TEvent]) => mixed, context?: mixed, - ): EventSubscription; + ): EmitterSubscription; emit>( eventType: TEvent, @@ -83,7 +83,7 @@ export default class EventEmitter< eventType: TEvent, listener: (...args: TEventToArgsMap[TEvent]) => mixed, context: mixed, - ): EventSubscription { + ): EmitterSubscription { if (typeof listener !== 'function') { throw new TypeError( 'EventEmitter.addListener(...): 2nd argument must be a function.', diff --git a/packages/react-native/Libraries/vendor/emitter/__tests__/EventEmitter-test.js b/packages/react-native/Libraries/vendor/emitter/__tests__/EventEmitter-test.js index 34ae1caebfee54..478613bffdbea2 100644 --- a/packages/react-native/Libraries/vendor/emitter/__tests__/EventEmitter-test.js +++ b/packages/react-native/Libraries/vendor/emitter/__tests__/EventEmitter-test.js @@ -9,7 +9,7 @@ * @oncall react_native */ -import type {EventSubscription} from '../EventEmitter'; +import type {EmitterSubscription} from '../EventEmitter'; import EventEmitter from '../EventEmitter'; @@ -350,7 +350,7 @@ describe('event emission', () => { results.push('C'); }); emitter.addListener('A', listenerA); - const subscriptionB: EventSubscription = emitter.addListener( + const subscriptionB: EmitterSubscription = emitter.addListener( 'A', listenerB, ); diff --git a/packages/react-native/src/private/animated/NativeAnimatedHelper.js b/packages/react-native/src/private/animated/NativeAnimatedHelper.js index 9ef311408a894c..d1ccf64f9c9b03 100644 --- a/packages/react-native/src/private/animated/NativeAnimatedHelper.js +++ b/packages/react-native/src/private/animated/NativeAnimatedHelper.js @@ -17,7 +17,7 @@ import type { AnimatedNodeConfig, EventMapping, } from '../../../Libraries/Animated/NativeAnimatedModule'; -import type {EventSubscription} from '../../../Libraries/vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from '../../../Libraries/vendor/emitter/EventEmitter'; import NativeAnimatedNonTurboModule from '../../../Libraries/Animated/NativeAnimatedModule'; import NativeAnimatedTurboModule from '../../../Libraries/Animated/NativeAnimatedTurboModule'; @@ -54,8 +54,8 @@ const eventListenerGetValueCallbacks: { const eventListenerAnimationFinishedCallbacks: { [number]: EndCallback, } = {}; -let globalEventEmitterGetValueListener: ?EventSubscription = null; -let globalEventEmitterAnimationFinishedListener: ?EventSubscription = null; +let globalEventEmitterGetValueListener: ?EmitterSubscription = null; +let globalEventEmitterAnimationFinishedListener: ?EmitterSubscription = null; function createNativeOperations(): $NonMaybeType { const methodNames = [ diff --git a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js index 576f82ce201672..7ecb7dbe16b0cf 100644 --- a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js +++ b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js @@ -11,7 +11,7 @@ 'use strict'; import type {PressEvent} from 'react-native/Libraries/Types/CoreEventTypes'; -import type {EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter'; import RNTesterBlock from '../../components/RNTesterBlock'; import RNTesterText from '../../components/RNTesterText'; @@ -1444,7 +1444,7 @@ class EnabledExample extends React.Component< state: {isEnabled: boolean} = { isEnabled: false, }; - _subscription: EventSubscription; + _subscription: EmitterSubscription; componentDidMount(): null | Promise { this._subscription = AccessibilityInfo.addEventListener( this.props.eventListener, diff --git a/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js index f4f32dbf5dc813..f3332246f02eec 100644 --- a/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js +++ b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js @@ -9,7 +9,7 @@ */ import type {RootTag} from 'react-native/Libraries/ReactNative/RootTag'; -import type {EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter'; import NativeCxxModuleExample, { EnumInt, @@ -73,7 +73,7 @@ type ErrorExamples = class NativeCxxModuleExampleExample extends React.Component<{}, State> { static contextType: React$Context = RootTagContext; - eventSubscriptions: EventSubscription[] = []; + eventSubscriptions: EmitterSubscription[] = []; state: State = { testResults: {}, diff --git a/packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js b/packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js index 9af1b932694e5e..6fe129f06206ab 100644 --- a/packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js +++ b/packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js @@ -9,7 +9,7 @@ */ import type {RootTag} from 'react-native/Libraries/ReactNative/RootTag'; -import type {EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter'; +import type {EmitterSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter'; import RNTesterText from '../../components/RNTesterText'; import styles from './TurboModuleExampleCommon'; @@ -64,7 +64,7 @@ type ErrorExamples = class SampleTurboModuleExample extends React.Component<{}, State> { static contextType: React$Context = RootTagContext; - eventSubscriptions: EventSubscription[] = []; + eventSubscriptions: EmitterSubscription[] = []; state: State = { testResults: {}, From 3eeb6e4eef9af6c4a7b22e2bf67f4fe439382b15 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 31 Jan 2025 04:55:45 -0800 Subject: [PATCH 3/3] Update RCTDeviceEventEmitter singleton instantiation Differential Revision: D68953499 --- .../Libraries/EventEmitter/RCTDeviceEventEmitter.js | 9 +++++---- scripts/build/build-types.js | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/react-native/Libraries/EventEmitter/RCTDeviceEventEmitter.js b/packages/react-native/Libraries/EventEmitter/RCTDeviceEventEmitter.js index b321c884b5f6ce..1f77685349b3fd 100644 --- a/packages/react-native/Libraries/EventEmitter/RCTDeviceEventEmitter.js +++ b/packages/react-native/Libraries/EventEmitter/RCTDeviceEventEmitter.js @@ -23,7 +23,7 @@ type RCTDeviceEventDefinitions = {[name: string]: Array}; * * NativeModules that emit events should instead subclass `NativeEventEmitter`. */ -class RCTDeviceEventEmitter extends EventEmitter { +class RCTDeviceEventEmitterImpl extends EventEmitter { // Add systrace to RCTDeviceEventEmitter.emit method for debugging emit>( eventType: TEvent, @@ -34,11 +34,12 @@ class RCTDeviceEventEmitter extends EventEmitter { endEvent(); } } -const instance = new RCTDeviceEventEmitter(); +const RCTDeviceEventEmitter: IEventEmitter = + new RCTDeviceEventEmitterImpl(); Object.defineProperty(global, '__rctDeviceEventEmitter', { configurable: true, - value: instance, + value: RCTDeviceEventEmitter, }); -export default (instance: IEventEmitter); +export default (RCTDeviceEventEmitter: IEventEmitter); diff --git a/scripts/build/build-types.js b/scripts/build/build-types.js index 70c455c911de30..dfe67a53fa85de 100644 --- a/scripts/build/build-types.js +++ b/scripts/build/build-types.js @@ -25,6 +25,7 @@ const SOURCE_PATTERNS = [ // Start with Animated only path.join(PACKAGES_DIR, 'react-native/Libraries/Alert/**/*.js'), path.join(PACKAGES_DIR, 'react-native/Libraries/vendor/**/*.js'), + path.join(PACKAGES_DIR, 'react-native/Libraries/EventEmitter/**/*.js'), path.join(PACKAGES_DIR, 'react-native/Libraries/TurboModule/RCTExport.js'), path.join(PACKAGES_DIR, 'react-native/Libraries/Types/RootTagTypes.js'), path.join(PACKAGES_DIR, 'react-native/Libraries/ReactNative/RootTag.js'),