Skip to main content

TypeScript

你可以在 Svelte 组件中使用 TypeScript。像 Svelte VS Code 扩展 这样的 IDE 扩展将帮助你在编辑器中捕获错误,而 svelte-check 在命令行上执行相同操作,你可以将其集成到你的 CI 中。

¥You can use TypeScript within Svelte components. IDE extensions like the Svelte VS Code extension will help you catch errors right in your editor, and svelte-check does the same on the command line, which you can integrate into your CI.

<script lang="ts">

要在 Svelte 组件中使用 TypeScript,请将 lang="ts" 添加到 script 标记中:

¥To use TypeScript inside your Svelte components, add lang="ts" to your script tags:

<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 编译器输出实际代码的功能。这包括:

¥Doing so allows you to use TypeScript’s type-only features. That is, all features that just disappear when transpiling to JavaScript, such as type annotations or interface declarations. Features that require the TypeScript compiler to output actual code are not supported. This includes:

  • 使用枚举

    ¥using enums

  • 在构造函数中与初始化器一起使用 privateprotectedpublic 修饰符

    ¥using private, protected or public modifiers in constructor functions together with initializers

  • 使用尚未成为 ECMAScript 标准一部分的功能(即不是 TC39 流程中的第 4 级),因此尚未在我们用于解析 JavaScript 的解析器 Acorn 中实现

    ¥using features that are not yet part of the ECMAScript standard (i.e. not level 4 in the TC39 process) and therefore not implemented yet within Acorn, the parser we use for parsing JavaScript

如果你想使用其中一个功能,则需要设置 script 预处理器。

¥If you want to use one of these features, you need to setup up a script preprocessor.

预处理器设置(Preprocessor setup)

¥Preprocessor setup

要在 Svelte 组件中使用非类型专用 TypeScript 功能,你需要添加一个将 TypeScript 转换为 JavaScript 的预处理器。

¥To use non-type-only TypeScript features within Svelte components, you need to add a preprocessor that will turn TypeScript into JavaScript.

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

const 
const config: {
    preprocess: PreprocessorGroup;
}
config
= {
// Note the additional `{ script: true }` preprocess: PreprocessorGrouppreprocess: function vitePreprocess(opts?: VitePreprocessOptions | undefined): 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(Using SvelteKit or Vite)

¥Using SvelteKit or Vite

最简单的入门方法是通过键入 npx sv create、按照提示并选择 TypeScript 选项来搭建一个新的 SvelteKit 项目。

¥The easiest way to get started is scaffolding a new SvelteKit project by typing npx sv create, following the prompts and choosing the TypeScript option.

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

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

如果你不需要或不想要 SvelteKit 提供的所有功能,则可以通过键入 npm create vite@latest 并选择 svelte-ts 选项来搭建 Svelte 风格的 Vite 项目。

¥If you don’t need or want all the features SvelteKit has to offer, you can scaffold a Svelte-flavoured Vite project instead by typing npm create vite@latest and selecting the svelte-ts option.

在这两种情况下,都会添加带有 vitePreprocesssvelte.config.js。Vite/SvelteKit 将从这个配置文件中读取。

¥In both cases, a svelte.config.js with vitePreprocess will be added. Vite/SvelteKit will read from this config file.

其他构建工具(Other build tools)

¥Other build tools

如果你使用 Rollup 或 Webpack 等工具,请安装它们各自的 Svelte 插件。对于 Rollup 来说是 rollup-plugin-svelte,对于 Webpack 来说是 svelte-loader。对于这两者,你需要安装 typescriptsvelte-preprocess 并将预处理器添加到插件配置中(有关更多信息,请参阅相应的 README)。如果你正在启动一个新项目,你还可以使用 rollupwebpack 模板从脚本中搭建设置。

¥If you’re using tools like Rollup or Webpack instead, install their respective Svelte plugins. For Rollup that’s rollup-plugin-svelte and for Webpack that’s svelte-loader. For both, you need to install typescript and svelte-preprocess and add the preprocessor to the plugin config (see the respective READMEs for more info). If you’re starting a new project, you can also use the rollup or webpack template to scaffold the setup from a script.

如果你正在开始一个新项目,我们建议改用 SvelteKit 或 Vite

¥[!NOTE] If you’re starting a new project, we recommend using SvelteKit or Vite instead

tsconfig.json 设置(tsconfig.json settings)

¥tsconfig.json settings

使用 TypeScript 时,请确保正确设置了 tsconfig.json

¥When using TypeScript, make sure your tsconfig.json is setup correctly.

  • 使用至少 ES2022target,或至少 ES2015targetuseDefineForClassFields。这可确保类字段上的符文声明不会被弄乱,否则会破坏 Svelte 编译器

    ¥Use a target of at least ES2022, or a target of at least ES2015 alongside useDefineForClassFields. This ensures that rune declarations on class fields are not messed with, which would break the Svelte compiler

  • verbatimModuleSyntax 设置为 true,以便将导入保持原样

    ¥Set verbatimModuleSyntax to true so that imports are left as-is

  • isolatedModules 设置为 true,以便单独查看每个文件。TypeScript 有一些功能需要跨文件分析和编译,而 Svelte 编译器和 Vite 等工具则不需要。

    ¥Set isolatedModules to true so that each file is looked at in isolation. TypeScript has a few features which require cross-file analysis and compilation, which the Svelte compiler and tooling like Vite don’t do.

键入 $props(Typing $props)

¥Typing $props

类型 $props 就像具有某些属性的常规对象一样。

¥Type $props just like a regular object with certain properties.

<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(Generic $props)

¥Generic $props

组件可以声明其属性之间的通用关系。一个例子是一个通用列表组件,它接收项目列表和一个从列表中接收项目的回调属性。要声明 items 属性和 select 回调对相同类型进行操作,请将 generics 属性添加到 script 标记:

¥Components can declare a generic relationship between their properties. One example is a generic list component that receives a list of items and a callback property that receives an item from the list. To declare that the items property and the select callback operate on the same types, add the generics attribute to the script tag:

<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 和后备类型。

¥The content of generics is what you would put between the <...> tags of a generic function. In other words, you can use multiple generics, extends and fallback types.

键入封装器组件(Typing wrapper components)

¥Typing wrapper components

如果你正在编写封装原生元素的组件,则可能希望向用户公开底层元素的所有属性。在这种情况下,使用(或扩展)svelte/elements 提供的接口之一。以下是 Button 组件的示例:

¥In case you’re writing a component that wraps a native element, you may want to expose all the attributes of the underlying element to the user. In that case, use (or extend from) one of the interfaces provided by svelte/elements. Here’s an example for a Button component:

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

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

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

通常,SvelteKit 首先在服务器上渲染你的页面,然后将该 HTML 发送到客户端,在那里它是 。对于没有 SvelteHTMLElements 的用户,请使用 SvelteHTMLElements

¥Not all elements have a dedicated type definition. For those without one, use SvelteHTMLElements:

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

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

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

键入 $state(Typing $state)

¥Typing $state

你可以像输入任何其他变量一样输入 $state

¥You can type $state like any other variable.

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

¥If you don’t give $state an initial value, part of its types will be undefined.

// Error: Type 'number | undefined' is not assignable to type '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 强制转换。这在类的上下文中特别有用:

¥If you know that the variable will be defined before you first use it, use an as casting. This is especially useful in the context of classes:

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; } }

Component 类型(The Component type)

¥The Component type

Svelte 组件属于 Component 类型。你可以使用它及其相关类型来表达各种约束。

¥Svelte components are of type Component. You can use it and its related types to express a variety of constraints.

将其与动态组件一起使用以限制可以传递给它的组件类型:

¥Using it together with dynamic components to restrict what kinds of component can be passed to it:

<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" />
Legacy mode

在 Svelte 4 中,组件属于 SvelteComponent 类型

¥[!LEGACY] In Svelte 4, components were of type SvelteComponent

要从组件中提取属性,请使用 ComponentProps

¥To extract the properties from a component, use 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>
) {} // 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>): voidwithProps(const MyComponent: LegacyComponentTypeMyComponent, { foo: stringfoo: 'bar' });

要声明变量需要组件的构造函数或实例类型:

¥To declare that a variable expects the constructor or instance type of a component:

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

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

<MyComponent bind:this={componentInstance} />

增强内置 DOM 类型(Enhancing built-in DOM types)

¥Enhancing built-in DOM types

Svelte 尽力提供了所有现有的 HTML DOM 类型。有时你可能想要使用来自操作的实验属性或自定义事件。在这些情况下,TypeScript 将抛出类型错误,表示它不知道这些类型。如果它是非实验性的标准属性/事件,这很可能是我们的 HTML 类型 中缺少的输入。在这种情况下,欢迎你提出问题和/或修复它的 PR。

¥Svelte provides a best effort of all the HTML DOM types that exist. Sometimes you may want to use experimental attributes or custom events coming from an action. In these cases, TypeScript will throw a type error, saying that it does not know these types. If it’s a non-experimental standard attribute/event, this may very well be a missing typing from our HTML typings. In that case, you are welcome to open an issue and/or a PR fixing it.

如果这是自定义或实验属性/事件,你可以像这样增强类型:

¥In case this is a custom or experimental attribute/event, you can enhance the typings like this:

additional-svelte-typings.d
declare namespace svelteHTML {
	// enhance elements
	interface interface svelteHTML.IntrinsicElementsIntrinsicElements {
		'my-custom-element': { someattribute: stringsomeattribute: 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) | undefinedonbeforeinstallprompt?: (event: anyevent: any) => any;
		// If you want to use myCustomAttribute={..} (note: all lowercase)
		svelteHTML.HTMLAttributes<T>.mycustomattribute?: anymycustomattribute?: any; // You can replace any with something more specific if you like
	}
}

然后确保 tsconfig.json 中引用了 d.ts 文件。如果它读取类似 "include": ["src/**/*"] 的内容并且你的 d.ts 文件在 src 内,它应该可以工作。你可能需要重新加载才能使更改生效。

¥Then make sure that d.ts file is referenced in your tsconfig.json. If it reads something like "include": ["src/**/*"] and your d.ts file is inside src, it should work. You may need to reload for the changes to take effect.

你还可以通过扩充 svelte/elements 模块来声明类型,如下所示:

¥You can also declare the typings by augmenting the svelte/elements module like this:

additional-svelte-typings.d
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 | undefinedveryexperimentalattribute?: string;
	}
}

export {}; // ensure this is not an ambient module, else types will be overridden instead of augmented
上一页 下一页