@ryoppippi

Event Types in Svelte and TypeScript

4 Nov 2023 ・ 4 min read


Note

この​記事はEvent Types in React and TypeScriptの​Svelte版です。 英語版は​気が​向いたら​書きます。

Note

この​記事では​Svelte 4.2.0以上を​前提と​しています。

Warning

この​記事では​HTML DOMの​型に​ついて​のみ​触れます。 Svelte Componentの​型の​扱いに​ついては​以下の​ドキュメントを​参照してください。 https://svelte.dev/docs/svelte#types-componentevents

The Problem

Svelteで​TypeScriptを​使っていると、​しばしば​この​種の​エラーに​遭遇する​ことが​あるでしょう。

<script lang="ts">
	// @errors: 7006
	const onChange = (e) => {};
</script>

<input on:change="{onChange}" />

onChange関数の​引数であるeに​どのような​型を​与えるべきかは​必ずしも​明確では​ありません。 DOMごとに​イベントには​異なる​型が​与えられている​ためです。

幸い、​いく​つか​解決策が​あります。

Solution 1: 仮の​関数を​渡し、​ホバーして​型を​コピーする

最初の​解決策は、on:changeに​仮の​関数を​渡して、​その​関数の​引数の​型を​ホバーして​コピーする​方​法です。

on:change hover

何やら​複雑な​型が​表示されていますが、​これを​コピーしてonChange関数の​型と​して​使う​ことができます。

<script lang="ts">
	const onChange = (
		e: Event & {
			currentTarget: EventTarget & HTMLInputElement;
		},
	) => {};
</script>

<input on:change="{onChange}" />

Solution 2: SvelteHTMLElementsから​型を​取得する

https://svelte.jp/docs/typescript#enhancing-built-in-dom-types

https://github.com/sveltejs/svelte/blob/5a8c1d2cafe8217aa1a6408b024571d3d655a431/packages/svelte/elements.d.ts

こちらに​HTML DOMの​型に​関する​記述が​あります。 これに​よれば、SvelteHTMLElementsから​DOMの​属性の​種類と​それぞれの​属性が​取るべき関数の​型を​取得する​ことができます。

<script lang="ts">
	import type { SvelteHTMLElements } from 'svelte/elements';

	type InputOnChangeEvent = SvelteHTMLElements['input']['on:change'];
	const onChange: NonNullable<InputOnChangeEvent> = (e) => {};
</script>

<input on:change="{onChange}" />

これに​より、onChangeの​引数eの​型を​決定できます。

Solution 3: Type Helperを​定義して​引数の​型を​取得する

Solution 2の​やり方は​うまく​行くのですが、​毎回SvelteHTMLElementsから​型情報を​取得するのは​面倒です。 その​ため、​Type Helperを​定義すると​便利です。

import type { EventHandler, SvelteHTMLElements } from 'svelte/elements';

type Nullish<T> = T | null | undefined;

type GetEventHandlers<T extends keyof SvelteHTMLElements> = Extract<
	keyof SvelteHTMLElements[T],
	`on:${string}`
>;

export type SvelteHTMLElementEvent<
	TElement extends keyof SvelteHTMLElements,
	THandler extends GetEventHandlers<TElement>
> = SvelteHTMLElements[TElement][THandler] extends Nullish<EventHandler<infer TEvent, infer _>>
	? TEvent
	: never;

この​Type Helperを​用いると、onChangeの​引数eに​与えるべき型を​簡単に​取得できます。

<script lang="ts">
	import type { SvelteHTMLElementEvent } from 'svelte-html-event';

	const onChange = (e: SvelteHTMLElementEvent<'input', 'on:change'>) => {};
</script>

<input on:change="{onChange}" />

この​コードは​ライブラリ化して​npmに​公開しているので、

bun install svelte-html-event

で​インストールできます。

https://github.com/ryoppippi/svelte-html-event

Note

ちなみに、​Svelteの​HTMLには​独自の​属性を​定義する​ことも​できます。 上記の​方法は​独自の​属性にも​対応しています。

https://svelte.dev/docs/typescript#enhancing-built-in-dom-types https://leaysgur.github.io/posts/2023/10/13/154305/

まとめ

すでに​自分の​関わっている​プロジェクトでは​Solution 3を​使っています。 皆さんも​是非​お試しください​〜

comment on bluesky / twitter
CC BY-NC-SA 4.0 2022-PRESENT © ryoppippi