From d33ff9fe7b3cf84f3051988f481949e25eabe292 Mon Sep 17 00:00:00 2001 From: John Flockton Date: Tue, 28 Oct 2025 02:57:00 -0700 Subject: [PATCH] Fix event listener option object types Summary: ### Context Currently, we're allowing users to pass in a lot of unnecessary options to `removeEventListener`. Flow supports [all of the `AddEventListenerOptions` flags](https://www.internalfb.com/code/fbsource/[af794e4e4e71]/www/html/xplat-react/flow/dom.js.flow?lines=333-341) for `removeEventListener` which is too permissive. Below is the DOM spec: ``` interface EventTarget { constructor(); undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options = {}); undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options = {}); boolean dispatchEvent(Event event); }; dictionary EventListenerOptions { boolean capture = false; }; dictionary AddEventListenerOptions : EventListenerOptions { boolean passive; boolean once = false; AbortSignal signal; }; ``` https://dom.spec.whatwg.org/#interface-eventtarget Only `capture` or `boolean` should ever be allowed for `removeEventListener` as a property key in an object or a straightforward boolean. For reference, here are the related TypeScript types which appear to [implement the above correctly](https://github.com/microsoft/TypeScript/blob/main/src/lib/dom.generated.d.ts#L8-L12). ### Diff This diff corrects the types and brings them more in line with the spec in `html/xplat-react/flow/dom.js.flow`, and then updates any erroring call sites in Flow. Differential Revision: D84544559 --- .../react-dom-bindings/src/client/ReactFiberConfigDOM.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 0af810924bbd7..3f97a768ebff4 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -2887,7 +2887,7 @@ export type FragmentInstanceType = { addEventListener( type: string, listener: EventListener, - optionsOrUseCapture?: EventListenerOptionsOrUseCapture, + optionsOrUseCapture?: AddEventListenerOptionsOrUseCapture, ): void, removeEventListener( type: string, @@ -2946,7 +2946,7 @@ function addEventListenerToChild( child: Fiber, type: string, listener: EventListener, - optionsOrUseCapture?: EventListenerOptionsOrUseCapture, + optionsOrUseCapture?: AddEventListenerOptionsOrUseCapture, ): boolean { const instance = getInstanceFromHostFiber(child); instance.addEventListener(type, listener, optionsOrUseCapture); @@ -2993,7 +2993,7 @@ function removeEventListenerFromChild( return false; } function normalizeListenerOptions( - opts: ?EventListenerOptionsOrUseCapture, + opts: ?AddEventListenerOptionsOrUseCapture, ): string { if (opts == null) { return '0'; @@ -3009,7 +3009,7 @@ function indexOfEventListener( eventListeners: Array, type: string, listener: EventListener, - optionsOrUseCapture: void | EventListenerOptionsOrUseCapture, + optionsOrUseCapture: void | AddEventListenerOptionsOrUseCapture, ): number { for (let i = 0; i < eventListeners.length; i++) { const item = eventListeners[i];