Skip to main content

Misc

TypeScript

Edit this page on GitHub

Svelte コンポーネント内では TypeScript が使用できます。Svelte VSCode extension などの IDE の拡張機能を使用すると、エディター上でエラーをすぐに見つけやすくなります。また、svelte-check は同じことをコマンドライン上で実行できるため、CI と統合できます。

セットアップ

Svelte コンポーネント内で TypeScript を使用するには、TypeScript を JavaScript に変換するプリプロセッサーを追加する必要があります。

SvelteKit または Vite を使用する

TypeScript を使い始めるのに最も簡単な方法は、npm create svelte@latest とタイプして、新しい SvelteKit プロジェクトを scaffold し、プロンプトに従って TypeScript オプションを選択することです。

svelte.config.js
ts
import { vitePreprocess } from '@sveltejs/kit/vite';
const config = {
preprocess: vitePreprocess()
};
export default config;

SvelteKit が提供するすべての機能が必要ではない場合は、npm create vite@latest とタイプして svelte-ts オプションを選ぶことで、Svelte 向けの Vite プロジェクトを scaffold できます。

svelte.config.js
ts
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
const config = {
preprocess: vitePreprocess()
};
export default config;

いずれの場合でも、vitePreprocess を使用した svelte.config.js が追加されます。Vite/SvelteKit はこの設定ファイルを読み込みます。

その他のビルドツール

代わりに Rollup や Webpack のようなツールを使用している場合、ツール向けの Svelte プラグインをインストールしてください。Rollup の場合は rollup-plugin-svelte、Webpack の場合はsvelte-loader です。どちらの場合も、typescriptsvelte-preprocess をインストールして、プリプロセッサーをプラグインの設定に追加する必要があります(より詳しい情報については、それぞれのREADMEを確認してください)。新しいプロジェクトを開始する場合には、rollupwebpack のテンプレートを使ってスクリプトからセットアップを scaffold することもできます。

新しいプロジェクトを開始する場合は、代わりに SvelteKit または Vite を使うことをおすすめします。

<script lang="ts">

Svelte コンポーネント内で TypeScript を使うには、lang="ts"script タグに追加します。

<script lang="ts">
	let name: string = 'world';

	function greet(name: string) {
		alert(`Hello, ${name}!`);
	}
</script>

Props

Props は、export let 文に直接型付けできます。

<script lang="ts">
	export let name: string;
</script>

Slots

Slot と slot prop の型は、渡された slot props の型から推論されます。

<script lang="ts">
	export let name: string;
</script>

<slot {name} />

<!-- Later -->
<Comp let:name>
	<!--    ^ string として推論される -->
	{name}
</Comp>

Events

Event は createEventDispatcher を使って型付けできます。

<script lang="ts">
	import { createEventDispatcher } from 'svelte';

	const dispatch = createEventDispatcher<{
		event: null; // payload を受け付けない
		click: string; // 必須の string の payload を持つ
		type: string | null; // オプションの string payload を持つ
	}>();

	function handleClick() {
		dispatch('event');
		dispatch('click', 'hello');
	}

	function handleType() {
		dispatch('event');
		dispatch('type', Math.random() > 0.5 ? 'world' : null);
	}
</script>

<button on:click={handleClick} on:keydown={handleType}>Click</button>

ビルトインのDOM型を拡張する

Svelte はベストエフォートで存在する全ての HTML DOM の型を提供します。ときには実験的な属性やアクションから来るカスタムイベントを使いたい場合があるかもしれません。そのような場合には、TypeScript が型エラーを発生し、未知の型であると報告します。もし実験的ではない標準の属性やイベントであるなら、Svelte の HTML 型 から来た型付けの誤りによる可能性があります。その場合、issue や修正の PR を歓迎します。

これがカスタムまたは実験的な属性またはイベントの場合、以下のように型を拡張できます。

additional-svelte-typings.d.ts
ts
declare namespace svelteHTML {
// 要素の拡張
interface IntrinsicElements {
'my-custom-element': { someattribute: string; 'on:event': (e: CustomEvent<any>) => void };
}
// 属性の拡張
interface HTMLAttributes<T> {
// on:beforeinstallprompt を使用したい場合
'on:beforeinstallprompt'?: (event: any) => any;
// myCustomAttribute={..} (注意: すべて小文字) を使用したい場合
mycustomattribute?: any; // 望むなら any をより特定の型に置き換えられます
}
}

そして、d.ts ファイルが tsconfig.json で参照されるようにします。"include": ["src/**/*"] のような設定があり、d.ts ファイルが src 内にあれば、上手く動作するはずです。変更を反映するためには再読み込みが必要なことがあります。

Svelte バージョン 4.2 / svelte-check バージョン 3.5 / VS Code 拡張機能 107.10.0 以降では、以下のように svelte/elements モジュールを拡張することでも型を宣言できるようになりました。

additional-svelte-typings.d.ts
ts
import { HTMLButtonAttributes } from 'svelte/elements';
declare module 'svelte/elements' {
export interface SvelteHTMLElements {
'custom-button': HTMLButtonAttributes;
}
// 型を追加する要素へのより細かい制御を可能にする
export interface HTMLButtonAttributes {
veryexperimentalattribute?: string;
}
}
export {}; // これが ambient module ではなく、他の型が拡張される代わりに上書きされることを保証する

実験的な高度な型付け

特定のインターフェイスを実装するコンポーネントの型付け、明示的に型付けされた slot、ジェネリクスの使用など、より高度なユースケースで TypeScript を最大限に活用するには、いくつかの機能が欠けています。これらの機能は、実験的な高度な型機能を利用することで実現可能です。使用方法に関するより詳しい情報は、この RFC を参照してください。

API は実験的であるため、いつでも変更される可能性があります

制限事項

マークアップ内ではTSは使えない

TypeScript はテンプレートのマークアップ内では使えません。たとえば、次のコードは機能しません。

<script lang="ts">
	let count = 10;
</script>

<h1>Count as string: {count as string}!</h1> <!-- ❌ 動かない -->
{#if count > 4}
	{@const countString: string = count} <!-- ❌ 動かない -->
	{countString}
{/if}

リアクティブな宣言

TypeScript を使用したリアクティブな宣言に対しては、変数と同じように型付けすることはできません。たとえば、次のコードは動作しません。

<script lang="ts">
	let count = 0;

	$: doubled: number = count * 2; // ❌ 動かない
</script>

この位置では無効な構文となるため、: TYPE を追加することはできません。その代わり、型の定義を直前の let 文に移動できます。

<script lang="ts">
	let count = 0;

	let doubled: number;
	$: doubled = count * 2;
</script>

Types

ComponentConstructorOptions

ts
interface ComponentConstructorOptions<
Props extends Record<string, any> = Record<string, any>
> {}
ts
target: Element | Document | ShadowRoot;
ts
anchor?: Element;
ts
props?: Props;
ts
context?: Map<any, any>;
ts
hydrate?: boolean;
ts
intro?: boolean;
ts
$$inline?: boolean;

ComponentEvents

Convenience type to get the events the given component expects. Example:

<script lang="ts">
   import type { ComponentEvents } from 'svelte';
   import Component from './Component.svelte';

   function handleCloseEvent(event: ComponentEvents<Component>['close']) {
	  console.log(event.detail);
   }
</script>

<Component on:close={handleCloseEvent} />
ts
type ComponentEvents<Component extends SvelteComponent_1> =
Component extends SvelteComponent<any, infer Events>
? Events
: never;

ComponentProps

Convenience type to get the props the given component expects. Example:

<script lang="ts">
	import type { ComponentProps } from 'svelte';
	import Component from './Component.svelte';

	const props: ComponentProps<Component> = { foo: 'bar' }; // Errors if these aren't the correct props
</script>
ts
type ComponentProps<Component extends SvelteComponent_1> =
Component extends SvelteComponent<infer Props>
? Props
: never;

ComponentType

Convenience type to get the type of a Svelte component. Useful for example in combination with dynamic components using <svelte:component>.

Example:

<script lang="ts">
	import type { ComponentType, SvelteComponent } from 'svelte';
	import Component1 from './Component1.svelte';
	import Component2 from './Component2.svelte';

	const component: ComponentType = someLogic() ? Component1 : Component2;
	const componentOfCertainSubType: ComponentType<SvelteComponent<{ needsThisProp: string }>> = someLogic() ? Component1 : Component2;
</script>

<svelte:component this={component} />
<svelte:component this={componentOfCertainSubType} needsThisProp="hello" />
ts
type ComponentType<
Component extends SvelteComponent = SvelteComponent
> = (new (
options: ComponentConstructorOptions<
Component extends SvelteComponent<infer Props>
? Props
: Record<string, any>
>
) => Component) & {
/** The custom element version of the component. Only present if compiled with the `customElement` compiler option */
element?: typeof HTMLElement;
};

SvelteComponent

Base class for Svelte components with some minor dev-enhancements. Used when dev=true.

Can be used to create strongly typed Svelte components.

Example:

You have component library on npm called component-library, from which you export a component called MyComponent. For Svelte+TypeScript users, you want to provide typings. Therefore you create a index.d.ts:

ts
import { SvelteComponent } from "svelte";
export class MyComponent extends SvelteComponent<{foo: string}> {}

Typing this makes it possible for IDEs like VS Code with the Svelte extension to provide intellisense and to use the component like this in a Svelte file with TypeScript:

<script lang="ts">
	import { MyComponent } from "component-library";
</script>
<MyComponent foo={'bar'} />
ts
class SvelteComponent<
Props extends Record<string, any> = any,
Events extends Record<string, any> = any,
Slots extends Record<string, any> = any
> extends SvelteComponent_1<Props, Events> {}
ts
[prop: string]: any;
ts
constructor(options: ComponentConstructorOptions<Props>);
ts
$capture_state(): void;
ts
$inject_state(): void;

SvelteComponentTyped

Use SvelteComponent instead. See PR for more information: https://github.com/sveltejs/svelte/pull/8512

ts
class SvelteComponentTyped<
Props extends Record<string, any> = any,
Events extends Record<string, any> = any,
Slots extends Record<string, any> = any
> extends SvelteComponent<Props, Events, Slots> {}