svelte icon indicating copy to clipboard operation
svelte copied to clipboard

Svelte 5: The `on` function types do not allow it to be used with `MediaQueryList`

Open Serator opened this issue 1 year ago • 6 comments

Describe the bug

Related to https://github.com/sveltejs/svelte/issues/12045

If this is a deliberate limitation, it's worth mentioning it in the documentation. Otherwise, it should be possible to use on with objects other than HTMLElement.

Reproduction

<script lang="ts">
	import {on} from 'svelte/events'

	$effect(() => {
		const matchMedia = window.matchMedia('(min-width: 1024px)')

		on(// <<< Argument of type 'MediaQueryList' is not assignable to parameter of type 'HTMLElement'.
		  matchMedia,
		  'change',

		  (event: MediaQueryListEvent) => {
		    console.log(event)
		  },
		)
	})
</script>

https://svelte-5-preview.vercel.app/#H4sIAAAAAAAAE1WQQWvDMAyF_4owAyeQNdvYKSSFHgo7tIfBbvMOXqKkhlgOttKuhPz34Wal3VGf9PT0NInW9BhE8TkJ0hZFITbDIDLB5yEW4Yg9o8hEcKOvIylD7c3A0GvqKiU4KLFWpNjYwXmGydEMrXcW5KLN8YjEQSqKUw_YtlhzkqRQrWGKSHHtKDBYzfVhj43RUMHJUONOqxtLZGINPZ5Mw4cCnp9eXoefVKbLVsWOkjyHsixh47vRIjG4FmIIkBf9-4j-vDOBJZgA5Bh0CKYj_d0jsINBe22R0d90bx_73bbHuEyuFhu4uzK7IlkfNHUos-sxAMkldAH_rbcR3gcHAIjhXY-r3nWLKr325j-HC5hTRWW-_H6tSGTCusa0BhtRsB9x_pp_AZJTOqDMAQAA

image

Logs

No response

System Info

Svelte 5.0.0-next.202

Severity

annoyance

Serator avatar Jul 30 '24 15:07 Serator

This is purely a TS bug, the playground shows that it works

dummdidumm avatar Jul 30 '24 16:07 dummdidumm

You don't need to use on on the MediaQueryList. Its only purpose is to attach event handlers to the DOM elements in a way that doesn't clash with the delegated event handlers.

7nik avatar Jul 30 '24 18:07 7nik

You don't need to use on on the MediaQueryList. Its only purpose is to attach event handlers to the DOM elements in a way that doesn't clash with the delegated event handlers.

In reality this can get annoying whenever you want an event more specific than Event

<script lang="ts">
	import {on} from 'svelte/events'

	$effect(() => {
		const input = document.querySelector("input");

		on(
		  input,
		  'input',
		  (event: InputEvent) => {
		    console.log(event)
		  },
		)
	})
</script>
image

paoloricciuti avatar Jul 30 '24 20:07 paoloricciuti

@7nik Do I understand correctly that delegation is used to reduce the number of listeners? Accordingly, in order not to reinvent the wheel, I can reuse the on function to delegate any events, even if they are not related to HTMLElement.

Serator avatar Jul 30 '24 23:07 Serator

I can reuse the on function to delegate any events

No, you can't because only common events are delegated: https://github.com/sveltejs/svelte/blob/5a05f6371a994286626a44168cb2c02f8a2ad567/packages/svelte/src/constants.js#L41-L65

Also, on doesn't delegate events at all but only prevents clashing with handlers added via the markup.

7nik avatar Jul 31 '24 08:07 7nik

Even if it did delegate, delegation means 'attaching an event listener to a single parent element rather than multiple child elements'. It's inherently element-centric; delegating a MediaQueryList event handler doesn't mean anything because it's not part of a tree. So there's really no advantage to using on over addEventListener (except maybe aesthetics).

Interestingly I can't reproduce it anyway — MediaQueryList looks to be a valid EventTarget? Not sure what TS config setting would be responsible for this:

image

Rich-Harris avatar Jul 31 '24 14:07 Rich-Harris