TypeScript
您可以在 Svelte 组件中使用 TypeScript。IDE 扩展,如 Svelte VS Code 扩展,可以帮助您在编辑器中直接捕获错误,而 svelte-check 则在命令行上执行相同的操作,您可以将它集成到您的 CI 中。
<script%20lang%3D"ts">
要在你的 Svelte 组件中使用 TypeScript,请将 lang="ts" 添加到你的 script 标签中:
<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 的解析器
如果您想使用这些功能之一,您需要设置一个 脚本 预处理器。
预处理设置
要使用仅在 TypeScript 中存在的功能在 Svelte 组件中,您需要添加一个将 TypeScript 转换为 JavaScript 的预处理器。
import { function vitePreprocess(opts?: VitePreprocessOptions): 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): import("svelte/compiler").PreprocessorGroupvitePreprocess({ VitePreprocessOptions.script?: boolean | undefinedpreprocess 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): 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 项目。
在两种情况下,都会添加一个 svelte.config.js,其中包含 vitePreprocess。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 设置正确。
- 使用至少
ES2015的目标,以便类不会被编译为函数 - 设置
verbatimModuleSyntax为true以便将导入保留原样 - 设置
isolatedModules为true,以便每个文件都可以独立检查。TypeScript 有一些需要跨文件分析和编译的功能,Svelte 编译器和像 Vite 这样的工具则不提供。
输入: Typing $props 输出: 输入: 输入 $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}内容为泛型的部分是你需要在泛型函数的<...>标签之间放置的内容。换句话说,你可以使用多个泛型、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>输入: Typing $state 输出: 输入:$state
您可以将 $state 当作任何其他变量来输入。
let let count: numbercount: number = function $state<0>(initial: 0): 0 (+1 overload)
namespace $state
$state(0);如果您没有给$state赋予初始值,其部分类型将变为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
$state();如果您知道变量将在您首次使用之前被定义,请使用一个作为类型转换。这在类的情况下尤其有用:
class class CounterCounter {
Counter.count: numbercount = function $state<number>(): number | undefined (+1 overload)
namespace $state
$state() as number;
constructor(initial: numberinitial: number) {
this.Counter.count: numbercount = initial: numberinitial;
}
}组件类型 组件
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 : neverConvenience 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>): 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<{ 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>): 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 : neverConvenience 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>): 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' });声明一个变量期望组件的构造函数或实例类型:
<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。
如果这是一个自定义或实验性的属性/事件,您可以通过增强 svelte/elements 模块来提升类型定义,如下所示:
import { HTMLButtonAttributes } from 'svelte/elements';
declare module 'svelte/elements' {
// add a new element
export interface SvelteHTMLElements {
'custom-button': HTMLButtonAttributes;
}
// add a new global attribute that is available on all html elements
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;
}
// add a new attribute for button elements
export interface HTMLButtonAttributes {
HTMLButtonAttributes.veryexperimentalattribute?: string | undefinedveryexperimentalattribute?: string;
}
}
export {}; // ensure this is not an ambient module, else types will be overridden instead of augmented确保在您的 tsconfig.json 中引用了 d.ts 文件。如果它看起来像这样 "include": ["src/**/*"] 并且您的 d.ts 文件位于 src 中,它应该可以正常工作。您可能需要重新加载以使更改生效。
Edit this page on GitHub llms.txt