@@ -371,17 +371,39 @@ export function emitWebIdl(
371371 obj : Browser . Typed ,
372372 forReturn : boolean ,
373373 ) : string {
374+ let type : string ;
374375 if ( obj . overrideType ) {
375- return obj . nullable ? makeNullable ( obj . overrideType ) : obj . overrideType ;
376+ type = obj . overrideType ;
377+ } else {
378+ if ( ! obj . type ) {
379+ throw new Error ( "Missing 'type' field in " + JSON . stringify ( obj ) ) ;
380+ }
381+ type = convertDomTypeToTsTypeWorker ( obj , forReturn ) ;
382+ if ( type === "Promise<undefined>" ) {
383+ type = "Promise<void>" ;
384+ }
376385 }
377- if ( ! obj . type ) {
378- throw new Error ( "Missing 'type' field in " + JSON . stringify ( obj ) ) ;
386+
387+ if ( obj . additionalTypes ) {
388+ const additional = obj . additionalTypes
389+ . filter ( ( t ) => t !== "undefined" )
390+ . map ( ( t ) => convertDomTypeToTsTypeSimple ( t ) ) ;
391+ if ( additional . length > 0 ) {
392+ type = distinct ( [ type , ...additional ] ) . join ( " | " ) ;
393+ }
379394 }
380- let type = convertDomTypeToTsTypeWorker ( obj , forReturn ) ;
381- if ( type === "Promise<undefined>" ) {
382- type = "Promise<void>" ;
395+
396+ if ( obj . nullable ) {
397+ type = makeNullable ( type ) ;
398+ }
399+
400+ if ( obj . additionalTypes ?. includes ( "undefined" ) ) {
401+ if ( ! type . split ( " | " ) . includes ( "undefined" ) ) {
402+ type += " | undefined" ;
403+ }
383404 }
384- return obj . nullable ? makeNullable ( type ) : type ;
405+
406+ return type ;
385407 }
386408
387409 function convertDomTypeToTsType ( obj : Browser . Typed ) {
@@ -408,22 +430,19 @@ export function emitWebIdl(
408430 return "Iterable" ;
409431 }
410432
411- if ( ! obj . additionalTypes && typeof obj . type === "string" ) {
433+ if ( typeof obj . type === "string" ) {
412434 return convertDomTypeToTsTypeSimple ( obj . type ) ;
413435 } else {
414- const types =
415- typeof obj . type === "string"
416- ? [ { ...obj , additionalTypes : undefined } ]
417- : obj . type ;
418- types . push ( ...( obj . additionalTypes ?? [ ] ) . map ( ( t ) => ( { type : t } ) ) ) ;
436+ const types = obj . type ;
419437
420438 // propagate `any`
421- const converted = types . map ( ( t ) =>
439+ let converted = types . map ( ( t ) =>
422440 convertDomTypeToTsTypeWorker ( t , forReturn ) ,
423441 ) ;
424442 if ( converted . includes ( "any" ) ) {
425443 return "any" ;
426444 }
445+ converted = distinct ( converted ) ;
427446
428447 // convert `ArrayBuffer | SharedArrayBuffer` into `ArrayBufferLike` to be pre-ES2017 friendly.
429448 const arrayBufferIndex = converted . indexOf ( "ArrayBuffer" ) ;
@@ -900,24 +919,28 @@ export function emitWebIdl(
900919 printer . printLine ( "/** @deprecated */" ) ;
901920 printer . printLine ( "declare const name: void;" ) ;
902921 } else {
903- let pType : string ;
922+ let pForType : Browser . Property = p ;
904923 if ( ! p . overrideType && isEventHandler ( p ) ) {
905924 // Sometimes event handlers with the same name may actually handle different
906925 // events in different interfaces. For example, "onerror" handles "ErrorEvent"
907926 // normally, but in "SVGSVGElement" it handles "SVGError" event instead.
908927 const eType = p . eventHandler
909928 ? getEventTypeInInterface ( p . eventHandler ! , i )
910929 : "Event" ;
911- pType = `(${ emitEventHandlerThis ( prefix , i ) } ev: ${ eType } ) => any` ;
930+ let typeStr = `(${ emitEventHandlerThis ( prefix , i ) } ev: ${ eType } ) => any` ;
912931 if ( typeof p . type === "string" && ! p . type . endsWith ( "NonNull" ) ) {
913- pType = `(${ pType } ) | null` ;
932+ typeStr = `(${ typeStr } ) | null` ;
914933 }
915- } else {
916- pType = convertDomTypeToTsType ( p ) ;
934+ pForType = { ...p , overrideType : typeStr } ;
917935 }
918- if ( p . optional ) {
919- pType += " | undefined" ;
936+ if ( pForType . optional ) {
937+ pForType = {
938+ ...pForType ,
939+ additionalTypes : [ ...( pForType . additionalTypes ?? [ ] ) , "undefined" ] ,
940+ } ;
920941 }
942+ const pType = convertDomTypeToTsType ( pForType ) ;
943+
921944 const propertyName = p . name . includes ( "-" ) ? `"${ p . name } "` : p . name ;
922945 const optionalModifier = ! p . optional || prefix ? "" : "?" ;
923946 const canPutForward =
@@ -934,10 +957,14 @@ export function emitWebIdl(
934957 if ( ! forwardingProperty ) {
935958 throw new Error ( "Couldn't find [PutForwards]" ) ;
936959 }
937- let setterType = `${ convertDomTypeToTsType ( forwardingProperty ) } ` ;
938- if ( ! compilerBehavior . allowUnrelatedSetterType ) {
939- setterType += ` | ${ pType } ` ;
940- }
960+ const setterType = convertDomTypeToTsType (
961+ compilerBehavior . allowUnrelatedSetterType
962+ ? forwardingProperty
963+ : {
964+ ...forwardingProperty ,
965+ type : [ forwardingProperty , pForType ] ,
966+ } ,
967+ ) ;
941968 printer . printLine (
942969 `set ${ propertyName } ${ optionalModifier } (${ p . putForwards } : ${ setterType } );` ,
943970 ) ;
@@ -1580,10 +1607,14 @@ export function emitWebIdl(
15801607 . sort ( compareName )
15811608 . forEach ( ( m ) => {
15821609 emitComments ( m , printer . printLine ) ;
1583- let type = convertDomTypeToTsType ( m ) ;
1584- if ( ! m . required && ! type . split ( " | " ) . includes ( "undefined" ) ) {
1585- type += " | undefined" ;
1586- }
1610+ const type = convertDomTypeToTsType (
1611+ m . required
1612+ ? m
1613+ : {
1614+ ...m ,
1615+ additionalTypes : [ ...( m . additionalTypes ?? [ ] ) , "undefined" ] ,
1616+ } ,
1617+ ) ;
15871618 printer . printLine ( `${ m . name } ${ m . required ? "" : "?" } : ${ type } ;` ) ;
15881619 } ) ;
15891620 }
0 commit comments