TypeScript 支持
本教程共 50 篇 · 第 38 篇 · 更新于 2026-08-05 · 约 6 分钟阅读
38. TypeScript 支持
本节目标:学会在 Svelte 5 组件中使用 TypeScript,掌握
$props()类型标注、泛型组件、ComponentProps类型工具和svelte-check命令行检查。
在组件中启用 TypeScript
给 <script> 标签加 lang="ts" 就能写 TypeScript:
<script lang="ts">
let name: string = 'world';
function greet(name: string): string {
return `Hello, ${name}!`;
}
</script>
<button onclick={() => alert(greet(name))}>
{name}
</button>
Svelte 的 VS Code 插件支持完整的类型检查,你写错类型时编辑器会立即标红。
Note
lang="ts"支持的是 TypeScript 的纯类型特性——类型标注、接口声明等编译后消失的东西。需要生成代码的特性(如 enum)需要额外配置预处理器。SvelteKit 项目默认已配好,开箱即用。
给 $props() 加类型
$props() 返回一个对象,你可以像普通变量一样给它加类型标注:
<script lang="ts">
interface Props {
title: string; // 必填
count?: number; // 可选
onclick?: () => void; // 回调函数
}
let { title, count = 0, onclick }: Props = $props();
</script>
<h1>{title}</h1>
<p>点击次数:{count}</p>
如果组件接收 snippet(内容插槽),用 Snippet 类型:
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
children: Snippet; // 无参数 snippet
itemRenderer: Snippet<[number]>; // 带参数 snippet
}
let { children, itemRenderer }: Props = $props();
</script>
{@render children()}
{#each [1, 2, 3] as item}
{@render itemRenderer(item)}
{/each}
泛型组件
有时候组件需要处理泛型类型。比如一个列表组件,接收 items 数组和一个 select 回调,两者应该操作同一种类型。给 script 标签加 generics 属性:
<script lang="ts" generics="Item extends { id: string }">
interface Props {
items: Item[];
onSelect: (item: Item) => void;
}
let { items, onSelect }: Props = $props();
</script>
{#each items as item (item.id)}
<button onclick={() => onSelect(item)}>
{item.id}
</button>
{/each}
generics 的内容就是你写在泛型函数 <...> 之间的部分。可以用多个泛型参数,也可以用 extends 约束。
使用时类型会自动推导:
<script lang="ts">
import List from './List.svelte';
interface User { id: string; name: string }
let users: User[] = [
{ id: '1', name: '张三' },
{ id: '2', name: '李四' }
];
function handleSelect(user: User) {
console.log(user.name);
}
</script>
<List items={users} onSelect={handleSelect} />
Tip泛型组件在做 UI 组件库时特别有用。比如
Select<T>、Table<T>这类通用组件,泛型保证传入的数据类型和回调参数类型一致。
$state 类型标注
$state 的类型标注和普通变量一样:
let count: number = $state(0);
let name: string = $state('hello');
let items: string[] = $state([]);
如果不给初始值,类型会包含 undefined:
// 类型是 number | undefined
let count: number = $state(); // 报错!
如果确定会在使用前赋值,用 as 断言:
class Counter {
count = $state() as number;
constructor(initial: number) {
this.count = initial;
}
}
Component 和 ComponentProps 类型
Svelte 5 提供了两个工具类型,用于在组件之间传递类型信息。
Component 类型表示一个 Svelte 组件的构造器,可以约束动态组件:
<script lang="ts">
import type { Component } from 'svelte';
import Button from './Button.svelte';
import Link from './Link.svelte';
interface Props {
dynamicComp: Component<{ label: string }>;
}
let { dynamicComp }: Props = $props();
</script>
<dynamicComp label="点击" />
ComponentProps 类型可以提取某个组件的 Props 类型:
import type { ComponentProps } from 'svelte';
import MyComponent from './MyComponent.svelte';
// MyComponentProps 等同于 MyComponent 的 Props 接口
type MyComponentProps = ComponentProps<typeof MyComponent>;
// 用在包装函数上
function renderWithDefaults(
component: typeof MyComponent,
props: Partial<ComponentProps<typeof MyComponent>>
) {
// ...
}
NoteSvelte 4 中组件类型是
SvelteComponent,Svelte 5 改为Component。迁移时需要替换类型引用。
包装原生元素的类型
写一个包装 <button> 的组件时,你可能想暴露 button 的所有原生属性。用 svelte/elements 提供的类型:
<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>
增强 DOM 类型
用了自定义属性或实验性 API 时,TypeScript 会报”不认识这个属性”。你可以通过模块增强来扩展类型定义:
// additional-svelte-typings.d.ts
import { HTMLButtonAttributes } from 'svelte/elements';
declare module 'svelte/elements' {
// 给 button 加自定义属性
export interface HTMLButtonAttributes {
'custom-attr'?: string;
}
// 给所有元素加全局属性
export interface HTMLAttributes<T> {
'data-theme'?: string;
}
}
export {}; // 确保是模块增强而非覆盖
Tip确保这个
.d.ts文件在tsconfig.json的include范围内。修改后可能需要重启编辑器才能生效。
tsconfig 配置
使用 TypeScript 时,tsconfig.json 需要注意几个设置:
{
"compilerOptions": {
"target": "ES2015",
"verbatimModuleSyntax": true,
"isolatedModules": true
}
}
| 设置 | 值 | 原因 |
|---|---|---|
target | ES2015+ | 避免类被编译成函数 |
verbatimModuleSyntax | true | 保持 import 原样,不自动转换 |
isolatedModules | true | 每个文件独立编译,适配 Vite 的单文件转译 |
SvelteKit 项目创建时已经配好这些,通常不需要手动改。
svelte-check
svelte-check 是命令行类型检查工具,相当于在终端运行编辑器里的类型检查:
npx svelte-check
它检查 .svelte 和 .svelte.js/.ts 文件中的类型错误和 a11y 警告。常用选项:
# 只检查不输出 tsconfig
npx svelte-check --tsconfig ./tsconfig.json
# 输出为人类可读详细格式
npx svelte-check --output human-verbose
# 监听文件变化
npx svelte-check --watch
Tip把
svelte-check加到 CI/CD 流程中,在代码合并前自动拦截类型错误。在package.json里加一个脚本:"check": "svelte-check --tsconfig ./tsconfig.json"。
本节回顾
<script lang="ts">启用 TypeScript,支持纯类型特性$props()用接口标注类型,snippet 用Snippet类型generics属性声明泛型组件,适合通用 UI 组件库Component和ComponentProps用于组件间的类型约束和提取svelte/elements提供原生 HTML 元素的属性类型svelte-check在命令行做类型检查,推荐接入 CI