Skip to main content

TypeScript

Svelte コンポーネント内で TypeScript を使えます。Svelte VS Code 拡張機能のようなIDE拡張機能はエディタ上でエラーをキャッチするのに役立ちます。また、 svelte-check はコマンドラインで同じことができ、CIに統合できます。

<script lang="ts">

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

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

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

<button onclick={(e: Event) => greet(e.target.innerText)}>
	{name as string}
</button>

これにより、 TypeScript の機能のうち 型のみ 使えます。つまり、型アノテーションやインターフェース宣言など、 JavaScript にトランスコンパイルすると消えてしまうすべての機能です。 TypeScript コンパイラが実際のコードを出力する必要のある機能はサポートされていません。これには以下が含まれます:

  • enumの使用
  • コンストラクタ関数で privateprotectedpublic 修飾子を初期化子(initializer)といっしょに使用する
  • ECMAScript 標準の一部ではない(つまりTC39プロセスでレベル4ではない)ため、 JavaScript 解析に用いるパーサー Acorn 内に実装されていない機能の使用

これらいずれかの機能を使いたいときは、 script プリプロセッサをセットアップする必要があります。

プリプロセッサのセットアップ

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

svelte.config
import { function vitePreprocess(opts?: VitePreprocessOptions): import("svelte/compiler").PreprocessorGroupvitePreprocess } from '@sveltejs/vite-plugin-svelte';

const 
const config: {
    preprocess: PreprocessorGroup;
}
config
= {
// `{ script: true }` の追加に注目してください preprocess: PreprocessorGrouppreprocess: function vitePreprocess(opts?: VitePreprocessOptions): import("svelte/compiler").PreprocessorGroupvitePreprocess({ VitePreprocessOptions.script?: boolean | undefined

preprocess script block with vite pipeline. Since svelte5 this is not needed for typescript anymore

@defaultfalse
script
: true })
}; export default
const config: {
    preprocess: PreprocessorGroup;
}
config
;

SvelteKit または Vite の使用

もっとも簡単な TypeScript の始め方は、 npx sv create と入力してプロンプトに従い、TypeScriptオプションを選択して新しい SvelteKit プロジェクトの骨組みを自動生成することです。

svelte.config
import { function vitePreprocess(opts?: VitePreprocessOptions): import("svelte/compiler").PreprocessorGroupvitePreprocess } from '@sveltejs/vite-plugin-svelte';

const 
const config: {
    preprocess: PreprocessorGroup;
}
config
= {
preprocess: PreprocessorGrouppreprocess: function vitePreprocess(opts?: VitePreprocessOptions): import("svelte/compiler").PreprocessorGroupvitePreprocess() }; export default
const config: {
    preprocess: PreprocessorGroup;
}
config
;

SvelteKit が提供するすべての機能が必要ない、または望まないときは、代わりに npm create vite@latest と入力し、 svelte-ts オプションを選択することで、 Svelte 風味の Vite プロジェクトの骨組みを自動生成できます。

どちらの場合も、vitePreprocess を含む svelte.config.js が追加されます。 Vite または SvelteKit は、この設定ファイルを読み取ります。

ほかのビルドツール

代わりに Rollup や Webpack のようなツールを使っているときは、それぞれの Svelte プラグインをインストールしてください。 RollUpの場合は rollup-plugin-svelte 、 WebPackの場合は svelte-loader です。両方とも、 typescriptsvelte-preprocess をインストールし、プリプロセッサをプラグイン設定に追加する必要があります(詳細は各READMEを参照)。新しいプロジェクトを開始するときは、 rollup または webpack テンプレートを使って、スクリプトから初期設定を自動生成することもできます。

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

tsconfig.json の設定

TypeScript を使うときは、 tsconfig.json が正しく設定されていることを確認してください。

  • クラスが関数にコンパイルされないように、 target を少なくとも ES2015 以降に設定してください。
  • インポートがそのまま残るように、 verbatimModuleSyntaxtrue に設定してください。
  • 各ファイルが個別に扱われるように、 isolatedModulestrue に設定してください。 TypeScript にはファイル間解析とコンパイルを必要とする機能がいくつかありますが、 Svelte コンパイラや Vite などのツールではこれをおこないません。

$props の型付け

$props を、特定のプロパティを持つ通常のオブジェクトと同じように型付けします。

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

	interface Props {
		requiredProperty: number;
		optionalProperty?: boolean;
		snippetWithStringArgument: Snippet<[string]>;
		eventHandler: (arg: string) => void;
		[key: string]: unknown;
	}

	let {
		requiredProperty,
		optionalProperty,
		snippetWithStringArgument,
		eventHandler,
		...everythingElse
	}: Props = $props();
</script>

<button onclick={() => eventHandler('clicked button')}>
	{@render snippetWithStringArgument('hello')}
</button>

ジェネリックな $props

コンポーネントのプロパティ間で、ジェネリクス(generics)を用いて型を関連づけることができます。例えば、汎用的なリストコンポーネントを考えてみましょう。このコンポーネントには、プロパティとして「アイテムのリスト」と「リストからアイテムを1つ受け取るコールバック関数」を渡すことができます。 そして、この items プロパティ(の配列)と select コールバック(の引数)が必ず同じ型であることを保証するために、 script タグに generics 属性を追加します。

<script lang="ts" generics="Item extends { text: string }">
	interface Props {
		items: Item[];
		select(item: Item): void;
	}

	let { items, select }: Props = $props();
</script>

{#each items as item}
	<button onclick={() => select(item)}>
		{item.text}
	</button>
{/each}

この generics 属性の書き方は、 TypeScript でジェネリック関数を定義するときの <...> (山括弧)内の構文とまったく同じです。言い換えると、複数のジェネリクス、 extends による型制約、デフォルトの型(フォールバック型)といった機能をそのまま利用できます。

ネイティブHTML要素をラップするコンポーネントの型付け

コンポーネントを作るとき、ラップしたネイティブHTML要素( button など)の標準属性( classdisabled など)を、コンポーネントを使う側で自由に指定したい場合があるでしょう。そのときは svelte/elements が提供する型定義(インターフェース)を使用(または継承)してください。以下は Button コンポーネントの例です:

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

	let { children, ...rest }: HTMLButtonAttributes = $props();
</script>

<button {...rest}>
	{@render children?.()}
</button>

すべての要素に専用の型定義が用意されているわけではありません。そのような要素には、 SvelteHTMLElements を使います:

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

	let { children, ...rest }: SvelteHTMLElements['div'] = $props();
</script>

<div {...rest}>
	{@render children?.()}
</div>

$state の型付け

$state はほかの変数と同じように型付けできます。

let let count: numbercount: number = 
function $state<0>(initial: 0): 0 (+1 overload)
namespace $state

Declares reactive state.

Example:

let count = $state(0);

https://svelte.dev/docs/svelte/$state

@paraminitial The initial value
$state
(0);

もし $state に初期値を設定しない場合、その型は undefined とのユニオン型になります。

// エラー: 型 'number | undefined' を型 'number' に割り当てることはできません
let let count: numbercount: number = 
function $state<number>(): number | undefined (+1 overload)
namespace $state

Declares reactive state.

Example:

let count = $state(0);

https://svelte.dev/docs/svelte/$state

@paraminitial The initial value
$state
();

変数の宣言時には値が決まっていなくても、後続の処理で 必ず 値がセットされる、とあなたが保証できるケースがあります。そのような場合は as キャストを使ってください。これはプロパティの初期化が constructor で行われるクラスで特に便利です:

class class CounterCounter {
	Counter.count: numbercount = 
function $state<number>(): number | undefined (+1 overload)
namespace $state

Declares reactive state.

Example:

let count = $state(0);

https://svelte.dev/docs/svelte/$state

@paraminitial The initial value
$state
() as number;
constructor(initial: numberinitial: number) { this.Counter.count: numbercount = initial: numberinitial; } }

コンポーネント自体の型

Svelte コンポーネントは Component 型です。 Component 型と関連する型を使って、さまざまな制約を表現できます。

例えば動的コンポーネントと組み合わせ、渡せるコンポーネントの種類を制限します:

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

	interface Props {
		// "prop" プロパティが必須であるコンポーネントのみを
		// DynamicComponentに渡すことができます
		DynamicComponent: Component<{ prop: string }>;
	}

	let { DynamicComponent }: Props = $props();
</script>

<DynamicComponent prop="foo" />
Legacy mode

Svelte 4 では、コンポーネントは SvelteComponent 型でした。

コンポーネントからプロパティを抽出するには、 ComponentProps を使います。

import type { interface Component<Props extends Record<string, any> = {}, Exports extends Record<string, any> = {}, Bindings extends keyof Props | "" = string>

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:

import type { Component } from 'svelte';
export declare const MyComponent: Component&#x3C;{ 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:

&#x3C;script lang="ts">
	import { MyComponent } from "component-library";
&#x3C;/script>
&#x3C;MyComponent foo={'bar'} />
Component
, type ComponentProps<Comp extends SvelteComponent | Component<any, any>> = Comp extends SvelteComponent<infer Props extends Record<string, any>, any, any> ? Props : Comp extends Component<infer Props extends Record<...>, any, string> ? Props : never

Convenience type to get the props the given component expects.

Example: Ensure a variable contains the props expected by MyComponent:

import type { ComponentProps } from 'svelte';
import MyComponent from './MyComponent.svelte';

// Errors if these aren't the correct props expected by MyComponent.
const props: ComponentProps&#x3C;typeof MyComponent> = { foo: 'bar' };

In Svelte 4, you would do ComponentProps&#x3C;MyComponent> because MyComponent was a class.

Example: A generic function that accepts some component and infers the type of its props:

import type { Component, ComponentProps } from 'svelte';
import MyComponent from './MyComponent.svelte';

function withProps&#x3C;TComponent extends Component&#x3C;any>>(
	component: TComponent,
	props: ComponentProps&#x3C;TComponent>
) {};

// Errors if the second argument is not the correct props expected by the component in the first argument.
withProps(MyComponent, { foo: 'bar' });
ComponentProps
} from 'svelte';
import
type MyComponent = SvelteComponent<Record<string, any>, any, any>
const MyComponent: LegacyComponentType
MyComponent
from './MyComponent.svelte';
function function withProps<TComponent extends Component<any>>(component: TComponent, props: ComponentProps<TComponent>): voidwithProps<function (type parameter) TComponent in withProps<TComponent extends Component<any>>(component: TComponent, props: ComponentProps<TComponent>): voidTComponent extends interface Component<Props extends Record<string, any> = {}, Exports extends Record<string, any> = {}, Bindings extends keyof Props | "" = string>

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:

import type { Component } from 'svelte';
export declare const MyComponent: Component&#x3C;{ 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:

&#x3C;script lang="ts">
	import { MyComponent } from "component-library";
&#x3C;/script>
&#x3C;MyComponent foo={'bar'} />
Component
<any>>(
component: TComponent extends Component<any>component: function (type parameter) TComponent in withProps<TComponent extends Component<any>>(component: TComponent, props: ComponentProps<TComponent>): voidTComponent, props: ComponentProps<TComponent>props: type ComponentProps<Comp extends SvelteComponent | Component<any, any>> = Comp extends SvelteComponent<infer Props extends Record<string, any>, any, any> ? Props : Comp extends Component<infer Props extends Record<...>, any, string> ? Props : never

Convenience type to get the props the given component expects.

Example: Ensure a variable contains the props expected by MyComponent:

import type { ComponentProps } from 'svelte';
import MyComponent from './MyComponent.svelte';

// Errors if these aren't the correct props expected by MyComponent.
const props: ComponentProps&#x3C;typeof MyComponent> = { foo: 'bar' };

In Svelte 4, you would do ComponentProps&#x3C;MyComponent> because MyComponent was a class.

Example: A generic function that accepts some component and infers the type of its props:

import type { Component, ComponentProps } from 'svelte';
import MyComponent from './MyComponent.svelte';

function withProps&#x3C;TComponent extends Component&#x3C;any>>(
	component: TComponent,
	props: ComponentProps&#x3C;TComponent>
) {};

// Errors if the second argument is not the correct props expected by the component in the first argument.
withProps(MyComponent, { foo: 'bar' });
ComponentProps
<function (type parameter) TComponent in withProps<TComponent extends Component<any>>(component: TComponent, props: ComponentProps<TComponent>): voidTComponent>
) {} // 第二引数が、第一引数のコンポーネントが期待するプロパティではないとき、 // エラーが発生します。 function withProps<LegacyComponentType>(component: LegacyComponentType, props: Record<string, any>): voidwithProps(const MyComponent: LegacyComponentTypeMyComponent, { foo: stringfoo: 'bar' });

コンポーネントのコンストラクタまたはインスタンス型を期待する変数を宣言するには:

<script lang="ts">
	import MyComponent from './MyComponent.svelte';

	let componentConstructor: typeof MyComponent = MyComponent;
	let componentInstance: MyComponent;
</script>

<MyComponent bind:this={componentInstance} />

組み込みDOM型の強化

Svelteは、存在するすべてのHTML DOMの型をできる限り提供しています。しかし、場合によっては、実験的な属性やアクション (action) 由来のカスタムイベントを使いたいことがあるかもしれません。そのようなケースでは、 TypeScript はそれらの型を認識できないため、型エラーを発生させます。もしそれが(実験的でない)標準の属性やイベントである場合、 Svelte が提供する HTMLの型定義 にその型が定義されていない可能性があります。そのときは、ぜひ issue を立てたり、修正のためのプルリクエストを送ってください。

もしこれがカスタムや実験的な属性・イベントであるときは、以下のように svelte/elements モジュールを拡張することで、型定義を強化できます:

additional-svelte-typings.d
import { HTMLButtonAttributes } from 'svelte/elements';

declare module 'svelte/elements' {
	// Svelteが認識するHTML要素のリストに、新しい要素(ここでは'custom-button')を追加します
	export interface SvelteHTMLElements {
		'custom-button': HTMLButtonAttributes;
	}

	// すべてのHTML要素で利用可能な新しいグローバル属性を追加します
	export interface interface HTMLAttributes<T extends EventTarget>HTMLAttributes<function (type parameter) T in HTMLAttributes<T extends EventTarget>T> {
		HTMLAttributes<T extends EventTarget>.globalattribute?: string | undefinedglobalattribute?: string;
	}

	// 特定の要素(ここでは<button>要素)に新しい属性を追加します
	export interface HTMLButtonAttributes {
		HTMLButtonAttributes.veryexperimentalattribute?: string | undefinedveryexperimentalattribute?: string;
	}
}

export {}; // これがアンビエントモジュールでないことを保証します。そうしないと、型が拡張(augmented)されるのではなく、上書き(overridden)されてしまいます。

次に、その d.ts ファイルが tsconfig.json で参照されていることを確認してください。もし "include": ["src/**/*"] のような記述があり、 d.ts ファイルが src 内にあるなら、強化した型定義は機能するはずです。変更を有効にするには、リロードが必要かもしれません。

Edit this page on GitHub llms.txt

previous next