Skip to content

Commit 7218146

Browse files
rubennortefacebook-github-bot
authored andcommitted
Allow parameterizing event types in EventTarget (#51700)
Summary: Pull Request resolved: #51700 Changelog: [internal] This adds the ability to strongly type `EventTarget` events via generics. See the next diff for an example of how to use it. Differential Revision: D75681184
1 parent a218b63 commit 7218146

13 files changed

Lines changed: 191 additions & 111 deletions

packages/react-native/Libraries/Blob/FileReader.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -179,51 +179,51 @@ class FileReader extends EventTarget {
179179
return this._result;
180180
}
181181

182-
get onabort(): EventCallback | null {
182+
get onabort(): EventCallback<> | null {
183183
return getEventHandlerAttribute(this, 'abort');
184184
}
185185

186-
set onabort(listener: ?EventCallback) {
186+
set onabort(listener: ?EventCallback<>) {
187187
setEventHandlerAttribute(this, 'abort', listener);
188188
}
189189

190-
get onerror(): EventCallback | null {
190+
get onerror(): EventCallback<> | null {
191191
return getEventHandlerAttribute(this, 'error');
192192
}
193193

194-
set onerror(listener: ?EventCallback) {
194+
set onerror(listener: ?EventCallback<>) {
195195
setEventHandlerAttribute(this, 'error', listener);
196196
}
197197

198-
get onload(): EventCallback | null {
198+
get onload(): EventCallback<> | null {
199199
return getEventHandlerAttribute(this, 'load');
200200
}
201201

202-
set onload(listener: ?EventCallback) {
202+
set onload(listener: ?EventCallback<>) {
203203
setEventHandlerAttribute(this, 'load', listener);
204204
}
205205

206-
get onloadstart(): EventCallback | null {
206+
get onloadstart(): EventCallback<> | null {
207207
return getEventHandlerAttribute(this, 'loadstart');
208208
}
209209

210-
set onloadstart(listener: ?EventCallback) {
210+
set onloadstart(listener: ?EventCallback<>) {
211211
setEventHandlerAttribute(this, 'loadstart', listener);
212212
}
213213

214-
get onloadend(): EventCallback | null {
214+
get onloadend(): EventCallback<> | null {
215215
return getEventHandlerAttribute(this, 'loadend');
216216
}
217217

218-
set onloadend(listener: ?EventCallback) {
218+
set onloadend(listener: ?EventCallback<>) {
219219
setEventHandlerAttribute(this, 'loadend', listener);
220220
}
221221

222-
get onprogress(): EventCallback | null {
222+
get onprogress(): EventCallback<> | null {
223223
return getEventHandlerAttribute(this, 'progress');
224224
}
225225

226-
set onprogress(listener: ?EventCallback) {
226+
set onprogress(listener: ?EventCallback<>) {
227227
setEventHandlerAttribute(this, 'progress', listener);
228228
}
229229
}

packages/react-native/Libraries/Network/XMLHttpRequest.js

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -83,46 +83,46 @@ const SUPPORTED_RESPONSE_TYPES = {
8383
};
8484

8585
class XMLHttpRequestEventTarget extends EventTarget {
86-
get onload(): EventCallback | null {
86+
get onload(): EventCallback<> | null {
8787
return getEventHandlerAttribute(this, 'load');
8888
}
89-
set onload(listener: ?EventCallback) {
89+
set onload(listener: ?EventCallback<>) {
9090
setEventHandlerAttribute(this, 'load', listener);
9191
}
92-
get onloadstart(): EventCallback | null {
92+
get onloadstart(): EventCallback<> | null {
9393
return getEventHandlerAttribute(this, 'loadstart');
9494
}
95-
set onloadstart(listener: ?EventCallback) {
95+
set onloadstart(listener: ?EventCallback<>) {
9696
setEventHandlerAttribute(this, 'loadstart', listener);
9797
}
98-
get onprogress(): EventCallback | null {
98+
get onprogress(): EventCallback<> | null {
9999
return getEventHandlerAttribute(this, 'progress');
100100
}
101-
set onprogress(listener: ?EventCallback) {
101+
set onprogress(listener: ?EventCallback<>) {
102102
setEventHandlerAttribute(this, 'progress', listener);
103103
}
104-
get ontimeout(): EventCallback | null {
104+
get ontimeout(): EventCallback<> | null {
105105
return getEventHandlerAttribute(this, 'timeout');
106106
}
107-
set ontimeout(listener: ?EventCallback) {
107+
set ontimeout(listener: ?EventCallback<>) {
108108
setEventHandlerAttribute(this, 'timeout', listener);
109109
}
110-
get onerror(): EventCallback | null {
110+
get onerror(): EventCallback<> | null {
111111
return getEventHandlerAttribute(this, 'error');
112112
}
113-
set onerror(listener: ?EventCallback) {
113+
set onerror(listener: ?EventCallback<>) {
114114
setEventHandlerAttribute(this, 'error', listener);
115115
}
116-
get onabort(): EventCallback | null {
116+
get onabort(): EventCallback<> | null {
117117
return getEventHandlerAttribute(this, 'abort');
118118
}
119-
set onabort(listener: ?EventCallback) {
119+
set onabort(listener: ?EventCallback<>) {
120120
setEventHandlerAttribute(this, 'abort', listener);
121121
}
122-
get onloadend(): EventCallback | null {
122+
get onloadend(): EventCallback<> | null {
123123
return getEventHandlerAttribute(this, 'loadend');
124124
}
125-
set onloadend(listener: ?EventCallback) {
125+
set onloadend(listener: ?EventCallback<>) {
126126
setEventHandlerAttribute(this, 'loadend', listener);
127127
}
128128
}
@@ -705,7 +705,7 @@ class XMLHttpRequest extends EventTarget {
705705
}
706706
}
707707

708-
addEventListener(type: string, listener: EventListener | null): void {
708+
addEventListener(type: string, listener: EventListener<> | null): void {
709709
// If we dont' have a 'readystatechange' event handler, we don't
710710
// have to send repeated LOADING events with incremental updates
711711
// to responseText, which will avoid a bunch of native -> JS
@@ -726,67 +726,67 @@ class XMLHttpRequest extends EventTarget {
726726
* `on<event>` event handling (without JS prototype magic).
727727
*/
728728

729-
get onabort(): EventCallback | null {
729+
get onabort(): EventCallback<> | null {
730730
return getEventHandlerAttribute(this, 'abort');
731731
}
732732

733-
set onabort(listener: ?EventCallback) {
733+
set onabort(listener: ?EventCallback<>) {
734734
setEventHandlerAttribute(this, 'abort', listener);
735735
}
736736

737-
get onerror(): EventCallback | null {
737+
get onerror(): EventCallback<> | null {
738738
return getEventHandlerAttribute(this, 'error');
739739
}
740740

741-
set onerror(listener: ?EventCallback) {
741+
set onerror(listener: ?EventCallback<>) {
742742
setEventHandlerAttribute(this, 'error', listener);
743743
}
744744

745-
get onload(): EventCallback | null {
745+
get onload(): EventCallback<> | null {
746746
return getEventHandlerAttribute(this, 'load');
747747
}
748748

749-
set onload(listener: ?EventCallback) {
749+
set onload(listener: ?EventCallback<>) {
750750
setEventHandlerAttribute(this, 'load', listener);
751751
}
752752

753-
get onloadstart(): EventCallback | null {
753+
get onloadstart(): EventCallback<> | null {
754754
return getEventHandlerAttribute(this, 'loadstart');
755755
}
756756

757-
set onloadstart(listener: ?EventCallback) {
757+
set onloadstart(listener: ?EventCallback<>) {
758758
setEventHandlerAttribute(this, 'loadstart', listener);
759759
}
760760

761-
get onprogress(): EventCallback | null {
761+
get onprogress(): EventCallback<> | null {
762762
return getEventHandlerAttribute(this, 'progress');
763763
}
764764

765-
set onprogress(listener: ?EventCallback) {
765+
set onprogress(listener: ?EventCallback<>) {
766766
setEventHandlerAttribute(this, 'progress', listener);
767767
}
768768

769-
get ontimeout(): EventCallback | null {
769+
get ontimeout(): EventCallback<> | null {
770770
return getEventHandlerAttribute(this, 'timeout');
771771
}
772772

773-
set ontimeout(listener: ?EventCallback) {
773+
set ontimeout(listener: ?EventCallback<>) {
774774
setEventHandlerAttribute(this, 'timeout', listener);
775775
}
776776

777-
get onloadend(): EventCallback | null {
777+
get onloadend(): EventCallback<> | null {
778778
return getEventHandlerAttribute(this, 'loadend');
779779
}
780780

781-
set onloadend(listener: ?EventCallback) {
781+
set onloadend(listener: ?EventCallback<>) {
782782
setEventHandlerAttribute(this, 'loadend', listener);
783783
}
784784

785-
get onreadystatechange(): EventCallback | null {
785+
get onreadystatechange(): EventCallback<> | null {
786786
return getEventHandlerAttribute(this, 'readystatechange');
787787
}
788788

789-
set onreadystatechange(listener: ?EventCallback) {
789+
set onreadystatechange(listener: ?EventCallback<>) {
790790
setEventHandlerAttribute(this, 'readystatechange', listener);
791791
}
792792
}

packages/react-native/Libraries/WebSocket/WebSocket.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -289,35 +289,35 @@ class WebSocket extends EventTarget {
289289
];
290290
}
291291

292-
get onclose(): EventCallback | null {
292+
get onclose(): EventCallback<> | null {
293293
return getEventHandlerAttribute(this, 'close');
294294
}
295295

296-
set onclose(listener: ?EventCallback) {
296+
set onclose(listener: ?EventCallback<>) {
297297
setEventHandlerAttribute(this, 'close', listener);
298298
}
299299

300-
get onerror(): EventCallback | null {
300+
get onerror(): EventCallback<> | null {
301301
return getEventHandlerAttribute(this, 'error');
302302
}
303303

304-
set onerror(listener: ?EventCallback) {
304+
set onerror(listener: ?EventCallback<>) {
305305
setEventHandlerAttribute(this, 'error', listener);
306306
}
307307

308-
get onmessage(): EventCallback | null {
308+
get onmessage(): EventCallback<> | null {
309309
return getEventHandlerAttribute(this, 'message');
310310
}
311311

312-
set onmessage(listener: ?EventCallback) {
312+
set onmessage(listener: ?EventCallback<>) {
313313
setEventHandlerAttribute(this, 'message', listener);
314314
}
315315

316-
get onopen(): EventCallback | null {
316+
get onopen(): EventCallback<> | null {
317317
return getEventHandlerAttribute(this, 'open');
318318
}
319319

320-
set onopen(listener: ?EventCallback) {
320+
set onopen(listener: ?EventCallback<>) {
321321
setEventHandlerAttribute(this, 'open', listener);
322322
}
323323
}

packages/react-native/src/private/webapis/dom/events/Event.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export default class Event {
6666
[COMPOSED_PATH_KEY]: boolean = [];
6767

6868
// $FlowExpectedError[unsupported-syntax]
69-
[CURRENT_TARGET_KEY]: EventTarget | null = null;
69+
[CURRENT_TARGET_KEY]: EventTarget<> | null = null;
7070

7171
// $FlowExpectedError[unsupported-syntax]
7272
[EVENT_PHASE_KEY]: boolean = Event.NONE;
@@ -84,7 +84,7 @@ export default class Event {
8484
[STOP_PROPAGATION_FLAG_KEY]: boolean = false;
8585

8686
// $FlowExpectedError[unsupported-syntax]
87-
[TARGET_KEY]: EventTarget | null = null;
87+
[TARGET_KEY]: EventTarget<> | null = null;
8888

8989
constructor(type: string, options?: ?EventInit) {
9090
if (arguments.length < 1) {
@@ -123,7 +123,7 @@ export default class Event {
123123
return this._composed;
124124
}
125125

126-
get currentTarget(): EventTarget | null {
126+
get currentTarget(): EventTarget<> | null {
127127
return getCurrentTarget(this);
128128
}
129129

@@ -139,7 +139,7 @@ export default class Event {
139139
return getIsTrusted(this);
140140
}
141141

142-
get target(): EventTarget | null {
142+
get target(): EventTarget<> | null {
143143
return getTarget(this);
144144
}
145145

@@ -151,7 +151,7 @@ export default class Event {
151151
return this._type;
152152
}
153153

154-
composedPath(): $ReadOnlyArray<EventTarget> {
154+
composedPath(): $ReadOnlyArray<EventTarget<>> {
155155
return getComposedPath(this).slice();
156156
}
157157

packages/react-native/src/private/webapis/dom/events/EventHandlerAttributes.js

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,33 @@
4040
* ```
4141
*/
4242

43+
import type Event from './Event';
4344
import type EventTarget from './EventTarget';
44-
import type {EventCallback} from './EventTarget';
45+
import type {EventCallback, GenericEventMap} from './EventTarget';
4546

46-
type EventHandler = $ReadOnly<{
47-
handleEvent: EventCallback,
47+
type EventHandler<EventTypes: Event> = $ReadOnly<{
48+
handleEvent: EventCallback<EventTypes>,
4849
}>;
49-
type EventHandlerAttributeMap = Map<string, EventHandler | null>;
50+
51+
type EventHandlerAttributeMap<EventTypes: GenericEventMap> = Map<
52+
$Keys<EventTypes>,
53+
EventHandler<$Values<EventTypes>> | null,
54+
>;
5055

5156
const EVENT_HANDLER_CONTENT_ATTRIBUTE_MAP_KEY = Symbol(
5257
'eventHandlerAttributeMap',
5358
);
5459

55-
function getEventHandlerAttributeMap(
56-
target: EventTarget,
57-
): ?EventHandlerAttributeMap {
60+
function getEventHandlerAttributeMap<EventTypes: GenericEventMap>(
61+
target: EventTarget<EventTypes>,
62+
): ?EventHandlerAttributeMap<EventTypes> {
5863
// $FlowExpectedError[prop-missing]
5964
return target[EVENT_HANDLER_CONTENT_ATTRIBUTE_MAP_KEY];
6065
}
6166

62-
function setEventHandlerAttributeMap(
63-
target: EventTarget,
64-
map: ?EventHandlerAttributeMap,
67+
function setEventHandlerAttributeMap<EventTypes: GenericEventMap>(
68+
target: EventTarget<EventTypes>,
69+
map: ?EventHandlerAttributeMap<EventTypes>,
6570
) {
6671
// $FlowExpectedError[prop-missing]
6772
target[EVENT_HANDLER_CONTENT_ATTRIBUTE_MAP_KEY] = map;
@@ -73,10 +78,13 @@ function setEventHandlerAttributeMap(
7378
*
7479
* Should be used to get the current value for `target.on{type}`.
7580
*/
76-
export function getEventHandlerAttribute(
77-
target: EventTarget,
78-
type: string,
79-
): EventCallback | null {
81+
export function getEventHandlerAttribute<
82+
EventTypes: GenericEventMap,
83+
EventType: $Keys<EventTypes>,
84+
>(
85+
target: EventTarget<EventTypes>,
86+
type: EventType,
87+
): EventCallback<EventTypes[EventType]> | null {
8088
const listener = getEventHandlerAttributeMap(target)?.get(type);
8189
return listener != null ? listener.handleEvent : null;
8290
}
@@ -87,10 +95,13 @@ export function getEventHandlerAttribute(
8795
*
8896
* Should be used to set a value for `target.on{type}`.
8997
*/
90-
export function setEventHandlerAttribute(
91-
target: EventTarget,
92-
type: string,
93-
callback: ?EventCallback,
98+
export function setEventHandlerAttribute<
99+
EventTypes: GenericEventMap,
100+
EventName: $Keys<EventTypes>,
101+
>(
102+
target: EventTarget<EventTypes>,
103+
type: EventName,
104+
callback: ?EventCallback<EventTypes[EventName]>,
94105
): void {
95106
let map = getEventHandlerAttributeMap(target);
96107
if (map != null) {

0 commit comments

Comments
 (0)