跳至主要內容

其他

TypeScript

在 GitHub 上編輯此頁面

您可以在 Svelte 元件中使用 TypeScript。IDE 擴充功能(例如 Svelte VSCode 擴充功能)將幫助您在編輯器中直接找出錯誤,而 svelte-check 則會在命令列中執行相同的動作,您可以將其整合到 CI 中。

設定

要在 Svelte 元件中使用 TypeScript,您需要新增一個預處理器,它會將 TypeScript 轉換成 JavaScript。

使用 SvelteKit 或 Vite

入門最簡單的方法是透過輸入 npm create svelte@latest 來建立一個新的 SvelteKit 專案,並依照提示選擇 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 專案。

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

在兩種情況下,都會新增一個包含 vitePreprocesssvelte.config.js。Vite/SvelteKit 會從這個設定檔讀取資料。

其他建置工具

如果你使用的是 Rollup 或 Webpack 等工具,請安裝它們各自的 Svelte 外掛程式。對於 Rollup,那是 rollup-plugin-svelte,而對於 Webpack,那是 svelte-loader。對於這兩個,你需要安裝 typescriptsvelte-preprocess,並將預處理器新增到外掛程式設定檔(請參閱各自的 README 以取得更多資訊)。如果你要開始一個新專案,你也可以使用 rollupwebpack 範本,從腳本建立設定。

如果你要開始一個新專案,我們建議改用 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>

屬性

屬性可以直接輸入在 export let 聲明中

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

插槽

插槽和插槽屬性類型會從傳遞給它們的插槽屬性類型中推論出來

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

<slot {name} />

<!-- Later -->
<Comp let:name>
	<!--    ^ Inferred as string -->
	{name}
</Comp>

事件

事件可以用 createEventDispatcher 輸入

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

	const dispatch = createEventDispatcher<{
		event: null; // does not accept a payload
		click: string; // has a required string payload
		type: string | null; // has an optional 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 會拋出類型錯誤,表示它不認識這些類型。如果這是非實驗性的標準屬性/事件,這很可能是我們的 HTML 輸入 中缺少輸入。在這種情況下,歡迎你開啟一個問題和/或一個 PR 來修復它。

如果這是一個自訂或實驗性屬性/事件,你可以這樣增強輸入

additional-svelte-typings.d.ts
ts
declare namespace svelteHTML {
// enhance elements
interface IntrinsicElements {
'my-custom-element': { someattribute: string; 'on:event': (e: CustomEvent<any>) => void };
}
// enhance attributes
interface HTMLAttributes<T> {
// If you want to use on:beforeinstallprompt
'on:beforeinstallprompt'?: (event: any) => any;
// If you want to use myCustomAttribute={..} (note: all lowercase)
mycustomattribute?: any; // You can replace any with something more specific if you like
}
}

然後確保你的 tsconfig.json 中有參照到 d.ts 檔案。如果它讀起來像 "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;
}
// allows for more granular control over what element to add the typings to
export interface HTMLButtonAttributes {
veryexperimentalattribute?: string;
}
}
export {}; // ensure this is not an ambient module, else types will be overridden instead of augmented

實驗性進階輸入

在更進階的使用案例中,例如輸入元件實作特定介面、明確輸入插槽或使用泛型,缺少一些功能才能充分利用 TypeScript。這些事情可以使用實驗性進階類型功能來完成。請參閱 此 RFC 以取得如何使用它們的更多資訊。

此 API 為實驗性質,且隨時可能變更

限制

標記中沒有 TS

您無法在範本的標記中使用 TypeScript。例如,下列範例無法運作

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

<h1>Count as string: {count as string}!</h1> <!-- ❌ Does not work -->
{#if count > 4}
	{@const countString: string = count} <!-- ❌ Does not work -->
	{countString}
{/if}

反應式宣告

您無法使用 TypeScript 為反應式宣告加上類型,就像您為變數加上類型一樣。例如,下列範例無法運作

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

	$: doubled: number = count * 2; // ❌ Does not work
</script>

您無法新增 : TYPE,因為在這個位置中,這是非法的語法。您可以將定義移至正上方的 let 陳述式

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

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

類型

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

方便的類型,用於取得給定元件預期的事件。範例

<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

方便的類型,用於取得給定元件預期的屬性。範例

<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

方便的類型,用於取得 Svelte 元件的類型。例如,與使用 <svelte:component> 的動態元件結合使用時,這會很有用。

範例

<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

Svelte 元件的基本類別,具有一些次要的開發增強功能。在 dev=true 時使用。

可用於建立強類型 Svelte 元件。

範例:

您在 npm 上有一個名為 component-library 的元件函式庫,您從中匯出一個名為 MyComponent 的元件。對於 Svelte+TypeScript 使用者,您想要提供類型化。因此,您建立一個 index.d.ts

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

輸入類型後,使用 Svelte 擴充功能的 IDE(例如 VS Code)就可以提供 IntelliSense,並在 Svelte 檔案中使用 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

請改用 SvelteComponent。有關更多資訊,請參閱 PR: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> {}