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 編譯器輸出實際程式碼的功能則不支援。這包括
- 使用列舉
- 在建構函式中搭配初始設定式使用
private
、protected
或public
修飾詞 - 使用尚未成為 ECMAScript 標準一部分(亦即在 TC39 流程中尚未達到第 4 級)的功能,因此 Acorn 中(我們用於剖析 JavaScript 的剖析器)尚未實作
如果您想要使用其中一個功能,您需要設定 script
預處理器。
預處理器設定
若要在 Svelte 元件內使用非僅類型 TypeScript 功能,您需要加入一個會將 TypeScript 轉換為 JavaScript 的預處理器。
import { function vitePreprocess(opts?: VitePreprocessOptions | undefined): import("svelte/compiler").PreprocessorGroup
vitePreprocess } from '@sveltejs/vite-plugin-svelte';
const const config: {
preprocess: PreprocessorGroup;
}
config = {
// Note the additional `{ script: true }`
preprocess: PreprocessorGroup
preprocess: function vitePreprocess(opts?: VitePreprocessOptions | undefined): import("svelte/compiler").PreprocessorGroup
vitePreprocess({ VitePreprocessOptions.script?: boolean | undefined
preprocess script block with vite pipeline.
Since svelte5 this is not needed for typescript anymore
script: true })
};
export default const config: {
preprocess: PreprocessorGroup;
}
config;
使用 SvelteKit 或 Vite
開始使用的最簡單方法是輸入 npx sv create
來建立新的 SvelteKit 專案,依照提示並選擇 TypeScript 選項。
import { function vitePreprocess(opts?: VitePreprocessOptions | undefined): import("svelte/compiler").PreprocessorGroup
vitePreprocess } from '@sveltejs/vite-plugin-svelte';
const const config: {
preprocess: PreprocessorGroup;
}
config = {
preprocess: PreprocessorGroup
preprocess: function vitePreprocess(opts?: VitePreprocessOptions | undefined): import("svelte/compiler").PreprocessorGroup
vitePreprocess()
};
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。對於這兩個外掛程式,您都需要安裝 typescript
和 svelte-preprocess
,並將預處理器加入到外掛程式設定中(如需更多資訊,請參閱各自的 README)。如果您要開始新的專案,您也可以使用 rollup 或 webpack 範本從指令碼建立設定。
如果您要開始新的專案,我們建議您改用 SvelteKit 或 Vite。
tsconfig.json 設定
使用 TypeScript 時,請確保您的 tsconfig.json
已正確設定。
- 使用至少
ES2022
的target
,或至少ES2015
的target
搭配useDefineForClassFields
。這可確保類別欄位上的符文宣告不會遭到干擾,否則會破壞 Svelte 編譯器 - 將
verbatimModuleSyntax
設定為true
,以便將匯入保持原狀 - 將
isolatedModules
設定為true
,以便個別檢視每個檔案。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
元件可以宣告其屬性之間的泛型關係。其中一個範例是一個泛型清單元件,該元件接收一個項目清單和一個回呼屬性,該屬性接收清單中的一個項目。若要宣告 items
屬性和 select
回呼對相同的類型進行操作,請將 generics
屬性加入到 script
標籤中
<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
的內容是您會放在泛型函式的 <...>
標籤之間的部分。換句話說,您可以使用多個泛型、extends
和回退類型。
類型化包裝元件
如果您正在撰寫一個包裝原生元素的元件,您可能想要將基礎元素的所有屬性公開給使用者。在這種情況下,請使用(或延伸自)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: number
count: number = function $state<0>(initial: 0): 0 (+1 overload)
namespace $state
Declares reactive state.
Example:
let count = $state(0);
$state(0);
如果您沒有給 $state
一個初始值,其類型的一部分將會是 undefined
。
// Error: Type 'number | undefined' is not assignable to type 'number'
let let count: number
count: number = function $state<number>(): number | undefined (+1 overload)
namespace $state
Declares reactive state.
Example:
let count = $state(0);
$state();
如果您知道變數在您第一次使用它之前將被定義,請使用 as
轉換。這在類別的內容中特別有用
class class Counter
Counter {
Counter.count: number
count = function $state<number>(): number | undefined (+1 overload)
namespace $state
Declares reactive state.
Example:
let count = $state(0);
$state() as number;
constructor(initial: number
initial: number) {
this.Counter.count: number
count = initial: number
initial;
}
}
Component 類型
Svelte 元件的類型為 Component
。您可以使用它及其相關的類型來表達各種限制。
將其與動態元件一起使用,以限制可以傳遞給它的元件種類
<script lang="ts">
import type { Component } from 'svelte';
interface Props {
// only components that have at most the "prop"
// property required can be passed
DynamicComponent: Component<{ prop: string }>;
}
let { DynamicComponent }: Props = $props();
</script>
<DynamicComponent prop="foo" />
舊版模式
在 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<{ 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'} />
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<typeof MyComponent> = { foo: 'bar' };
In Svelte 4, you would do ComponentProps<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<TComponent extends Component<any>>(
component: TComponent,
props: ComponentProps<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>): void
withProps<function (type parameter) TComponent in withProps<TComponent extends Component<any>>(component: TComponent, props: ComponentProps<TComponent>): void
TComponent 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<{ 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'} />
Component<any>>(
component: TComponent extends Component<any>
component: function (type parameter) TComponent in withProps<TComponent extends Component<any>>(component: TComponent, props: ComponentProps<TComponent>): void
TComponent,
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<typeof MyComponent> = { foo: 'bar' };
In Svelte 4, you would do ComponentProps<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<TComponent extends Component<any>>(
component: TComponent,
props: ComponentProps<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>): void
TComponent>
) {}
// Errors if the second argument is not the correct props expected
// by the component in the first argument.
function withProps<LegacyComponentType>(component: LegacyComponentType, props: Record<string, any>): void
withProps(const MyComponent: LegacyComponentType
MyComponent, { foo: string
foo: '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 類型。有時您可能想要使用來自動作的實驗性屬性或自訂事件。在這些情況下,TypeScript 會擲回類型錯誤,表示它不了解這些類型。如果這是非實驗性的標準屬性/事件,這很可能表示我們的 HTML 類型定義遺失了類型。在這種情況下,歡迎您開啟問題和/或 PR 來修正它。
如果這是自訂或實驗性屬性/事件,您可以使用如下方式來增強類型定義
declare namespace svelteHTML {
// enhance elements
interface interface svelteHTML.IntrinsicElements
IntrinsicElements {
'my-custom-element': { someattribute: string
someattribute: string; 'on:event': (e: CustomEvent<any>
e: interface CustomEvent<T = any>
CustomEvent<any>) => void };
}
// enhance attributes
interface interface svelteHTML.HTMLAttributes<T>
HTMLAttributes<function (type parameter) T in HTMLAttributes<T>
T> {
// If you want to use the beforeinstallprompt event
svelteHTML.HTMLAttributes<T>.onbeforeinstallprompt?: ((event: any) => any) | undefined
onbeforeinstallprompt?: (event: any
event: any) => any;
// If you want to use myCustomAttribute={..} (note: all lowercase)
svelteHTML.HTMLAttributes<T>.mycustomattribute?: any
mycustomattribute?: any; // You can replace any with something more specific if you like
}
}
然後確保您的 tsconfig.json
中參考了 d.ts
檔案。如果它讀取類似 "include": ["src/**/*"]
的內容,而您的 d.ts
檔案位於 src
內部,它應該可以運作。您可能需要重新載入,變更才會生效。
您也可以使用如下方式來擴充 svelte/elements
模組來宣告類型定義
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 {
HTMLButtonAttributes.veryexperimentalattribute?: string | undefined
veryexperimentalattribute?: string;
}
}
export {}; // ensure this is not an ambient module, else types will be overridden instead of augmented