Language-tools: Support custom events on native DOM elements

Created on 5 Aug 2020  ·  4Comments  ·  Source: sveltejs/language-tools

Is your feature request related to a problem? Please describe.
I get the following error when I'm trying to add custom events on native DOM elements:

Type '{ onswipestart: (event: CustomEvent<any>) => void; onswipemove: (event: CustomEvent<any>) => void; onswipeend: (event: CustomEvent<any>) => void; style: string; class: string; }' is not assignable to type 'HTMLProps<HTMLDivElement>'.
  Property 'onswipestart' does not exist on type 'HTMLProps<HTMLDivElement>'.ts(2322)

The custom events are dispatched to a div element using Sveltes actions/use directive https://svelte.dev/examples#actions).

Describe the solution you'd like
Be able to type check for custom events dispatched using Svelte actions on native DOM elements.

Describe alternatives you've considered
I could try to convert the div to an individual Svelte component but preferably it should work on native DOM elements as well.

Additional context

The error message

This is how I listen to the custom events:

<div
  class="bottomSheet"
  class:draggable
  bind:this={bottomSheet}
  use:swipeable
  on:swipestart={handleSwipeStart}
  on:swipemove={handleSwipeMove}
  on:swipeend={handleSwipeEnd}
  style="height:{height};bottom:{bottom};transform:translateY({$coords.ty}px);"
>

Related Pull Request for custom events on Svelte components: https://github.com/sveltejs/language-tools/pull/303

enhancement

Most helpful comment

Don't know if there is a way to make it only applies to elements with the action. but you can make it globally available like this.

declare namespace svelte.JSX {
    interface HTMLAttributes<T> {
        onswipemove?: (event: CustomEvent<number> & { target: EventTarget & T }) => any;
    }
}

All 4 comments

Don't know if there is a way to make it only applies to elements with the action. but you can make it globally available like this.

declare namespace svelte.JSX {
    interface HTMLAttributes<T> {
        onswipemove?: (event: CustomEvent<number> & { target: EventTarget & T }) => any;
    }
}

We could also enhance our typings with "fall back to CustomEvent<any> but I'd rather not do it because others may rely on the typings to throw a "does not exist" error if they mistype an event. I would be okay with something like that if it's only applied to elements with actions, but I'm not sure how we would implement that.
To infer the type from the action is an almost impossible task I think. Maybe we can find a way to let the user explicitly type the action and its possible events.

Thanks, letting the user explicitly type the action or explicitly choose when to fall back to CustomEvent<any> would probably be the best case scenario but the solution by @jasonlyu123 is good enough for me now. Thanks for the great work!

I had a look at this again and now I'm split on what's the best way forward.

Option 1: Silence error

We could silence the error if it's a on:XX event on a DOM element with a use:YY directive. The drawback is that the event is of type any implicitly. It also may not catch all cases, because Svelte is so dynamic in its nature, someone could do bubbling CustomEvents.

Option 2: Add CustomEvent<any> fallback

We would essentially add & {[key: string]: CustomEvent<any>} to all instrinsic element typings. This means _any_ attribute that is not listed above will fall back to CustomEvent<any>. This would fix the "dynamic nature" problem and the "implicit any" problem of option 1. But it is also wrong in cases someone uses a custom attribute like myownAttribute.

Option 3: Add any fallback

Like option 2, only that we add a & {[key: string]: any} fallback. This means anything that does not fit falls back to any. This fits the dynamic nature of the DOM the best at the cost of not catching typos anymore.

Was this page helpful?
0 / 5 - 0 ratings