@@ -305,7 +305,7 @@ module InputJson =
305305
306306 let getItemByName ( allItems : InputJsonType.Root []) ( itemName : string ) ( kind : ItemKind ) otherFilter =
307307 let filter ( item : InputJsonType.Root ) =
308- OptionCheckValue itemName item.Name &&
308+ ( OptionCheckValue itemName item.Name || OptionCheckValue ( sprintf " %s ? " itemName ) item.Name ) &&
309309 item.Kind.ToLower() = kind.ToString() &&
310310 otherFilter item
311311 allItems |> Array.tryFind filter
@@ -660,6 +660,7 @@ module Data =
660660 |> Array.map ( fun i -> ( i.Name, getEventHandler i))
661661 |> Map.ofArray
662662
663+ // Map of interface.Name -> List of base interfaces with event handlers
663664 let iNameToEhParents =
664665 let hasHandler ( i : Browser.Interface ) =
665666 iNameToEhList.ContainsKey i.Name && not iNameToEhList.[ i.Name]. IsEmpty
@@ -1035,6 +1036,16 @@ module Emit =
10351036 | Some comment -> printLine " %s " comment
10361037 | _ -> ()
10371038
1039+ // A covariant EventHandler is one that is defined in a parent interface as then redefined in current interface with a more specific argument types
1040+ // These patterns are unsafe, and flagged as error under --strictFunctionTypes.
1041+ // Here we know the property is already defined on the interface, we elide its declaration if the parent has the same handler defined
1042+ let isCovariantEventHandler ( p : Browser.Property ) =
1043+ p.Type = " EventHandler" &&
1044+ iNameToEhParents.ContainsKey i.Name &&
1045+ not iNameToEhParents.[ i.Name]. IsEmpty &&
1046+ iNameToEhParents.[ i.Name]
1047+ |> List.exists ( fun i -> iNameToEhList.ContainsKey i.Name && not iNameToEhList.[ i.Name]. IsEmpty && iNameToEhList.[ i.Name] |> List.exists ( fun e -> e.Name = p.Name))
1048+
10381049 let emitProperty ( p : Browser.Property ) =
10391050 let printLine content =
10401051 if conflictedMembers.Contains p.Name then Pt.PrintlToStack content else Pt.Printl content
@@ -1071,6 +1082,7 @@ module Emit =
10711082 | Some ps ->
10721083 ps.Properties
10731084 |> Array.filter ( ShouldKeep flavor)
1085+ |> Array.filter ( isCovariantEventHandler >> not )
10741086 |> Array.iter emitProperty
10751087 | None -> ()
10761088
@@ -1096,7 +1108,12 @@ module Emit =
10961108 // Otherwise, this is EventTarget.addEventListener, we want to keep that.
10971109 let mFilter ( m : Browser.Method ) =
10981110 matchScope emitScope m &&
1099- not ( prefix <> " " && OptionCheckValue " addEventListener" m.Name)
1111+ not (
1112+ prefix <> " " && (
1113+ ( OptionCheckValue " addEventListener" m.Name) ||
1114+ ( OptionCheckValue " removeEventListener" m.Name)
1115+ )
1116+ )
11001117
11011118 let emitMethod flavor prefix ( i : Browser.Interface ) ( m : Browser.Method ) =
11021119 let printLine content =
@@ -1179,30 +1196,43 @@ module Emit =
11791196 | _ -> ()
11801197
11811198 let EmitEventHandlers ( flavor : Flavor ) ( prefix : string ) ( i : Browser.Interface ) =
1199+ let getOptionsType ( addOrRemove : string ) =
1200+ if addOrRemove = " add" then " AddEventListenerOptions" else " EventListenerOptions"
1201+
11821202 let fPrefix =
11831203 if prefix.StartsWith " declare var" then " declare function " else " "
11841204
1185- let emitEventHandler prefix ( iParent : Browser.Interface ) =
1205+ let emitTypedEventHandler ( prefix : string ) ( addOrRemove : string ) ( iParent : Browser.Interface ) =
1206+ Pt.Printl
1207+ " %s%s EventListener<K extends keyof %s EventMap>(type: K, listener: (this: %s , ev: %s EventMap[K]) => any, options?: boolean | %s ): void;"
1208+ prefix addOrRemove iParent.Name i.Name iParent.Name ( getOptionsType addOrRemove)
1209+
1210+ let emitStringEventHandler ( addOrRemove : string ) =
11861211 Pt.Printl
1187- " %s addEventListener<K extends keyof %s EventMap> (type: K , listener: (this: %s , ev: %s EventMap[K]) => any, useCapture ?: boolean): void;"
1188- prefix iParent.Name i.Name iParent.Name
1212+ " %s%s EventListener (type: string , listener: EventListenerOrEventListenerObject, options ?: boolean | %s ): void;"
1213+ fPrefix addOrRemove ( getOptionsType addOrRemove )
11891214
1190- let shouldEmitStringEventHandler =
1215+ let tryEmitTypedEventHandlerForInterface ( addOrRemove : string ) =
11911216 if iNameToEhList.ContainsKey i.Name && not iNameToEhList.[ i.Name]. IsEmpty then
1192- emitEventHandler fPrefix i
1217+ emitTypedEventHandler fPrefix addOrRemove i
11931218 true
11941219 elif iNameToEhParents.ContainsKey i.Name && not iNameToEhParents.[ i.Name]. IsEmpty then
11951220 iNameToEhParents.[ i.Name]
11961221 |> List.sortBy ( fun i -> i.Name)
1197- |> List.iter ( emitEventHandler fPrefix)
1222+ |> List.iter ( emitTypedEventHandler fPrefix addOrRemove )
11981223 true
11991224 else
12001225 false
12011226
1202- if shouldEmitStringEventHandler then
1203- Pt.Printl
1204- " %s addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;"
1205- fPrefix
1227+ let emitEventHandler ( addOrRemove : string ) =
1228+ if tryEmitTypedEventHandlerForInterface addOrRemove then
1229+ // only emit the string event handler if we just emited a typed handler
1230+ emitStringEventHandler addOrRemove
1231+
1232+
1233+ emitEventHandler " add"
1234+ emitEventHandler " remove"
1235+
12061236
12071237 let EmitConstructorSignature flavor ( i : Browser.Interface ) =
12081238 let emitConstructorSigFromJson ( c : InputJsonType.Root ) =
@@ -1500,7 +1530,11 @@ module Emit =
15001530 | _ -> Pt.Printl " interface %s extends %s {" dict.Name dict.Extends
15011531
15021532 let emitJsonProperty ( p : InputJsonType.Root ) =
1503- Pt.Printl " %s : %s ;" p.Name.Value p.Type.Value
1533+ let readOnlyModifier =
1534+ match p.Readonly with
1535+ | Some( true ) -> " readonly "
1536+ | _ -> " "
1537+ Pt.Printl " %s%s : %s ;" readOnlyModifier p.Name.Value p.Type.Value
15041538
15051539 let removedPropNames =
15061540 getRemovedItems ItemKind.Property flavor
0 commit comments