Svelte 是较新的 JavaScript 框架之一,并且正在迅速普及。它是一个基于模板的框架,但允许在模板绑定中使用任意 JavaScript;它具有出色的响应式特性,简单、灵活且有效;并且作为一个提前 (AOT) 编译的框架,它拥有令人印象深刻的性能和包大小。这篇文章将重点介绍如何在 Svelte 模板中配置 TypeScript。如果您不熟悉 Svelte,我建议您查看 入门教程 和 文档。
如果您想跟随代码(或者您想调试在您自己的项目中可能缺少的内容),您可以 克隆仓库。我设置了分支来演示我将要介绍的各个部分。
注意:虽然我们将手动集成 Svelte 和 Typescript,但如果您正在启动一个新的项目,您可能会考虑使用 官方的 Svelte 模板,它可以实现相同的功能。无论哪种方式,这篇文章都涵盖了 TypeScript 配置,即使您使用模板,它仍然相关。
基本的 TypeScript 和 Svelte 设置
让我们来看一下基础设置。如果您转到仓库中的 initial-setup
分支,则设置了一个基本的 Svelte 项目,并使用了 TypeScript。需要明确的是,TypeScript 仅在独立的 .ts
文件中工作。它没有以任何方式集成到 Svelte 中。**实现 TypeScript 集成是本文的目的。**
我将介绍一些使 Svelte 和 TypeScript 协同工作的部分,主要是因为我稍后会更改它们,以便向 Svelte 模板添加 TypeScript 支持。
首先,我有一个 tsconfig.json
文件
{
"compilerOptions": {
"module": "esNext",
"target": "esnext",
"moduleResolution": "node"
},
"exclude": ["./node_modules"]
}
此文件告诉 TypeScript 我想要使用现代 JavaScript、使用 Node 解析以及从编译中排除 node_modules
。
然后,在 typings/index.d.ts
中,我有以下内容
declare module "*.svelte" {
const value: any;
export default value;
}
这允许 TypeScript 与 Svelte 共存。如果没有它,TypeScript 每次使用导入语句加载 Svelte 文件时都会发出错误。最后,我们需要告诉 webpack 处理我们的 Svelte 文件,我们通过 webpack.config.js
中的此规则来实现
{
test: /\.(html|svelte)$/,
use: [
{ loader: "babel-loader" },
{
loader: "svelte-loader",
options: {
emitCss: true,
},
},
],
}
所有这些都是使用 Svelte 组件和 TypeScript 文件的项目的的基本设置。要确认一切都能构建,请打开几个终端并在其中一个中运行 npm start
,这将启动 webpack 监视,并在另一个中运行 npm run tscw
,以启动 TypeScript 监视任务。希望两者都能在没有错误的情况下运行。要真正验证 TypeScript 检查是否正在运行,您可以更改
let x: number = 12;
…在 index.ts
中为
let x: number = "12";
…并查看 TypeScript 监视中出现的错误。如果您想实际运行它,您可以在第三个终端中运行 node server
(我推荐 iTerm2,它允许您在同一窗口的选项卡中运行这些终端),然后点击 localhost:3001
。
向 Svelte 添加 TypeScript
让我们直接向 Svelte 组件添加 TypeScript,然后查看我们需要进行哪些配置更改才能使其工作。首先转到 Helper.svelte
,并在 script 标签中添加 lang="ts"
。这告诉 Svelte script 中有 TypeScript。现在让我们实际添加一些 TypeScript。让我们通过 export let val: number;
将 val
属性检查为数字。整个组件现在如下所示
<script lang="ts">
export let val: number;
</script>
<h1>Value is: {val}</h1>
我们的 webpack 窗口现在应该出现错误,但这是预期的。

我们需要告诉 Svelte 加载程序如何处理 TypeScript。让我们安装以下内容
npm i svelte-preprocess svelte-check --save
现在,让我们转到我们的 webpack 配置文件并获取 svelte-preprocess
const sveltePreprocess = require("svelte-preprocess");
…并将其添加到我们的 svelte-loader 中
{
test: /\.(html|svelte)$/,
use: [
{ loader: "babel-loader" },
{
loader: "svelte-loader",
options: {
emitCss: true,
preprocess: sveltePreprocess({})
},
},
],
}
好的,让我们重新启动 webpack 进程,它应该可以构建。
添加检查
到目前为止,我们拥有的内容可以构建,但它没有进行检查。如果我们的 Svelte 组件中存在无效代码,我们希望它生成错误。因此,让我们转到 App.svelte
,在 script 标签中添加相同的 lang="ts"
,然后为 val
属性传递一个无效值,如下所示
<Helper val={"3"} />
如果我们查看 TypeScript 窗口,没有错误,但应该有。事实证明,我们没有使用普通的 tsc 编译器来检查 Svelte 模板的类型,而是使用我们之前安装的 svelte-check 实用程序。让我们停止我们的 TypeScript 监视,并在该终端中运行 npm run svelte-check
。这将在监视模式下启动 svelte-check 进程,我们应该会看到我们期望的错误。

现在,删除 3
周围的引号,错误应该消失

不错!
在实践中,我们希望同时运行 svelte-check 和 tsc,以便我们在 TypeScript 文件和 Svelte 模板中捕获所有错误。npm 上有很多实用程序可以做到这一点,或者我们可以使用 iTerm2,它能够在同一窗口中拆分多个终端。我在这里使用它来运行服务器、webpack 构建、tsc 构建和 svelte-check 构建。

此设置位于仓库的 basic-checking
分支中。
捕获缺少的属性
我们还需要解决一个问题。如果我们省略了必需的属性,例如我们刚刚看到的 val
属性,我们仍然不会收到错误,但我们应该收到,因为我们没有在 Helper.svelte
中为它分配默认值,因此它是必需的。
<Helper /> // missing `val` prop
要告诉 TypeScript 将此报告为错误,让我们回到我们的 tsconfig
,并添加两个新值
"strict": true,
"noImplicitAny": false
第一个启用默认情况下禁用的许多 TypeScript 检查。第二个 noImplicitAny
将其中一项严格检查关闭。如果没有第二行,任何缺少类型的变量(隐式类型为 any
)现在都会被报告为错误(没有隐式 any,明白了吗?)
关于是否应将 noImplicitAny
设置为 true
,意见**存在很大分歧**。我个人认为它过于严格,但很多人不同意。进行实验并得出自己的结论。
无论如何,有了新的配置,我们应该能够重新启动 svelte-check 任务并看到我们期望的错误。

此设置位于仓库的 better-checking
分支中。
其他细节
需要注意的是,如果组件曾经引用过 $$props
或 $$restProps
,那么 TypeScript 用于捕获不正确属性的机制将立即且不可逆地关闭。例如,如果您要将一个未声明的属性(例如 junk
)传递给 Helper 组件,您将收到预期的错误,因为该组件没有 junk
属性。但是,如果 Helper
组件引用了 $$props
或 $$restProps
,则此错误将立即消失。前者允许您动态访问任何属性,而无需为其进行显式声明,而 $$restProps
用于动态访问未声明的属性。
当您考虑它时,这是有道理的。这些构造的目的是动态地即时访问属性,通常用于某种元编程,或者将属性任意地传递给 html 元素,这在 UI 库中很常见。它们的存在意味着对可能未声明的组件的任意访问。
$$props
还有另一种常见用法,那就是访问声明为保留字的属性。class
是一个常见的例子。例如
const className = $$props.class;
…因为
export let class = "";
…是无效的。class
是 JavaScript 中的保留字,但在此特定情况下有一个解决方法。以下也是声明同一属性的有效方法——感谢 Rich Harris 提供帮助。
let className;
export { className as class };
如果您唯一使用 $$props
的目的是访问名称为保留字的属性,您可以使用此替代方法,并为您的组件维护更好的类型检查。
结束语
Svelte 是我使用过的最有前途、最高效,坦率地说也是最有趣的 JavaScript 框架之一。可以相对轻松地添加 TypeScript 就像锦上添花。让 TypeScript 及早为您捕获错误可以真正提高生产力。希望这篇文章对实现这一目标有所帮助。
为什么不使用官方的 svelte-typescript 模板仓库?你可以直接使用 npx degit sveltejs/template my-svelte-project,然后运行 node scripts/setupTypeScript.js,就完成了。
嘿,谢谢你的分享。我之前不知道有这个,我会考虑在文章中添加一个说明。也就是说,这里的内容对于那些希望向现有项目添加 TS 支持的人来说仍然很有价值。
非常感谢这个教程。你救了我的工作!
谢谢。你提供的与官方仓库不同的方法。官方使用 tsc,而这个使用 babel。这帮助我构建了我们的仓库。即使使用 babel,似乎仍然需要 tsconfig.json。
如果你创建了一个与你的组件同名的单独的 .d.ts 文件,你可以输入 `$$restProps`。
参见 https://github.com/bestguy/sveltestrap/blob/master/src/Card.d.ts 以了解一个流行库的示例。