@@ -346,52 +346,81 @@ function buildEventHandlerType(
346
346
elementName : string ,
347
347
eventName : string
348
348
) {
349
- const nativeEventHandlerType = [
350
- `(e:` ,
351
- /**/ `'${ eventName } ' extends infer EVT` ,
352
- /**/ /**/ `?EVT extends keyof HTMLElementEventMap` ,
353
- /**/ /**/ /**/ `?HTMLElementEventMap[EVT]` ,
354
- /**/ /**/ /**/ `:CustomEvent<any>` ,
355
- /**/ /**/ `:never` ,
356
- `)=>void` ,
357
- ] . join ( "" ) ;
349
+ const nativeEventHandlerType = `(e:${ conditional ( {
350
+ check : `'${ eventName } '` ,
351
+ extends : `infer EVT` ,
352
+ true : conditional ( {
353
+ check : `EVT` ,
354
+ extends : `keyof HTMLElementEventMap` ,
355
+ true : `HTMLElementEventMap[EVT]` ,
356
+ false : `CustomEvent<any>` ,
357
+ } ) ,
358
+ false : `never` ,
359
+ } ) } )=>void`;
358
360
if ( element . type !== "SvelteElement" ) {
359
361
return nativeEventHandlerType ;
360
362
}
361
363
if ( element . kind === "component" ) {
362
- // `@typescript-eslint/parser` currently cannot parse `*.svelte` import types correctly.
363
- // So if we try to do a correct type parsing, it's argument type will be `any`.
364
- // A workaround is to inject the type directly, as `CustomEvent<any>` is better than `any`.
365
-
366
- // const componentEvents = `import('svelte').ComponentEvents<${elementName}>`;
367
- // return `(e:'${eventName}' extends keyof ${componentEvents}?${componentEvents}['${eventName}']:CustomEvent<any>)=>void`;
368
-
369
- return `(e:CustomEvent<any>)=>void` ;
364
+ const componentEventsType = `import('svelte').ComponentEvents<${ elementName } >` ;
365
+ return `(e:${ conditional ( {
366
+ check : `0` ,
367
+ extends : `(1 & ${ componentEventsType } )` ,
368
+ // `componentEventsType` is `any`
369
+ // `@typescript-eslint/parser` currently cannot parse `*.svelte` import types correctly.
370
+ // So if we try to do a correct type parsing, it's argument type will be `any`.
371
+ // A workaround is to inject the type directly, as `CustomEvent<any>` is better than `any`.
372
+ true : `CustomEvent<any>` ,
373
+ // `componentEventsType` has an exact type.
374
+ false : conditional ( {
375
+ check : `'${ eventName } '` ,
376
+ extends : `infer EVT` ,
377
+ true : conditional ( {
378
+ check : `EVT` ,
379
+ extends : `keyof ${ componentEventsType } ` ,
380
+ true : `${ componentEventsType } [EVT]` ,
381
+ false : `CustomEvent<any>` ,
382
+ } ) ,
383
+ false : `never` ,
384
+ } ) ,
385
+ } ) } )=>void`;
370
386
}
371
387
if ( element . kind === "special" ) {
372
388
if ( elementName === "svelte:component" ) return `(e:CustomEvent<any>)=>void` ;
373
389
return nativeEventHandlerType ;
374
390
}
375
391
const attrName = `on:${ eventName } ` ;
376
- const importSvelteHTMLElements =
377
- "import('svelte/elements').SvelteHTMLElements" ;
378
- return [
379
- `'${ elementName } ' extends infer EL` ,
380
- /**/ `?(` ,
381
- /**/ /**/ `EL extends keyof ${ importSvelteHTMLElements } ` ,
382
- /**/ /**/ `?(` ,
383
- /**/ /**/ /**/ `'${ attrName } ' extends infer ATTR` ,
384
- /**/ /**/ /**/ `?(` ,
385
- /**/ /**/ /**/ /**/ `ATTR extends keyof ${ importSvelteHTMLElements } [EL]` ,
386
- /**/ /**/ /**/ /**/ /**/ `?${ importSvelteHTMLElements } [EL][ATTR]` ,
387
- /**/ /**/ /**/ /**/ /**/ `:${ nativeEventHandlerType } ` ,
388
- /**/ /**/ /**/ `)` ,
389
- /**/ /**/ /**/ `:never` ,
390
- /**/ /**/ `)` ,
391
- /**/ /**/ `:${ nativeEventHandlerType } ` ,
392
- /**/ `)` ,
393
- /**/ `:never` ,
394
- ] . join ( "" ) ;
392
+ const svelteHTMLElementsType = "import('svelte/elements').SvelteHTMLElements" ;
393
+ return conditional ( {
394
+ check : `'${ elementName } '` ,
395
+ extends : "infer EL" ,
396
+ true : conditional ( {
397
+ check : `EL` ,
398
+ extends : `keyof ${ svelteHTMLElementsType } ` ,
399
+ true : conditional ( {
400
+ check : `'${ attrName } '` ,
401
+ extends : "infer ATTR" ,
402
+ true : conditional ( {
403
+ check : `ATTR` ,
404
+ extends : `keyof ${ svelteHTMLElementsType } [EL]` ,
405
+ true : `${ svelteHTMLElementsType } [EL][ATTR]` ,
406
+ false : nativeEventHandlerType ,
407
+ } ) ,
408
+ false : `never` ,
409
+ } ) ,
410
+ false : nativeEventHandlerType ,
411
+ } ) ,
412
+ false : `never` ,
413
+ } ) ;
414
+
415
+ /** Generate `C extends E ? T : F` type. */
416
+ function conditional ( types : {
417
+ check : string ;
418
+ extends : string ;
419
+ true : string ;
420
+ false : string ;
421
+ } ) {
422
+ return `${ types . check } extends ${ types . extends } ?(${ types . true } ):(${ types . false } )` ;
423
+ }
395
424
}
396
425
397
426
/** Convert for Class Directive */
0 commit comments