---
title: "配置 TypeScript"
description: "Deno 中 TypeScript 配置指南。了解编译器选项、JavaScript 的类型检查、JSDoc 支持、类型声明以及跨平台兼容性的 TypeScript 配置。"
oldUrl:
- /runtime/manual/advanced/typescript/faqs/
- /runtime/manual/advanced/typescript/migration/
- /runtime/manual/advanced/typescript/configuration/
- /runtime/manual/advanced/typescript/types/
- /runtime/manual/typescript/types/
- /runtime/manual/advanced/faqs/
- /runtime/advanced/typescript/configuration/
- /runtime/manual/typescript/typescript/faqs/
- /runtime/fundamentals/types/
---
Deno 的灵活性体现在对 TypeScript 和 JavaScript 的平等对待。
无论您是从 JavaScript 迁移到 TypeScript,还是反之,Deno
都提供了便利功能来帮助您顺利过渡。
## JavaScript 的类型检查
您可能希望使您的 JavaScript 更加符合类型,而不必在每个地方添加类型注解。Deno 支持使用 TypeScript 类型检查器来检查 JavaScript 的类型。您可以通过向文件添加检查 JavaScript 的 pragma 来标记单个文件:
```js
// @ts-check
```
这将导致类型检查器推断 JavaScript 代码的类型信息,并将任何问题作为诊断问题提出。
您可以通过提供配置文件并将 check JS 选项设置为 `true` 来为程序中的所有 JavaScript 文件启用此功能,如下所示。然后在命令行运行时使用 `--config` 选项。
```json
{
"compilerOptions": {
"checkJs": true
}
}
```
## 在 JavaScript 中使用 JSDoc
在对 JavaScript 进行类型检查或将 JavaScript 导入到 TypeScript 时,JSDoc 注释可以提供超出代码本身可以推断的额外类型信息。如果您在代码中以支持的
[TypeScript JSDoc](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html) 进行内联注释,Deno 将无缝支持这一点。
例如,要设置数组的类型,可以使用以下 JSDoc 注释:
```js
/** @type {string[]} */
const a = [];
```
## 跳过类型检查
您可能有正在尝试的 TypeScript 代码,其中语法有效但并不完全安全。您可以通过传递 `--no-check` 标志来绕过整个程序的类型检查。
如果您已启用 check JS,还可以通过使用 `nocheck` pragma 跳过整个文件的类型检查,包括 JavaScript:
```js
// @ts-nocheck
```
## 将 JS 文件重命名为 TS 文件
TypeScript 文件受益于 TypeScript 编译器能够对您的代码进行更彻底的安全检查。这通常被称为 _严格模式_。
当您将 `.js` 文件重命名为 `.ts` 时,您可能会看到 TypeScript 之前无法检测到的新类型错误。
## 在 Deno 中配置 TypeScript
Deno 致力于基于以下设计原则简化 TypeScript 配置:
- 对类型检查规则采用严格且现代的默认值。
- 允许省略涉及目标运行时或兼容性的设置,利用与执行环境的直接集成。
- 使用 `deno.json` 目录作用域支持项目引用。
最后一点提供了比 `tsconfig.json` 的 [`references`](https://www.typescriptlang.org/tsconfig/#references) 和 [`extends`](https://www.typescriptlang.org/tsconfig/#extends) 字段更简洁的格式,使用 `deno.json` 工作区和根成员继承。详见关于[工作区中的类型检查](/runtime/fundamentals/workspaces/#type-checking)章节。
## `tsconfig.json` 兼容性
虽然不推荐在以 Deno 为主的项目中使用 [`tsconfig.json`](https://www.typescriptlang.org/tsconfig/) 文件,但现有的 Node.js + TypeScript 工作区仍可在 Deno 的类型检查器和语言服务器协议中开箱即用。
对包含 `deno.json` 或 `package.json` 的每个工作区目录,Deno 都会查找 `tsconfig.json` 文件。如果存在,它将被添加为“根”项目引用,并递归包含其中的引用。
与 `tsc` 类似,TSConfig 的作用域由其[根字段](https://www.typescriptlang.org/tsconfig/#root-fields)确定。如有重叠情况:
- 被引用的项目优先于引用者。
- 对于根引用,`foo/bar/tsconfig.json` 优先于 `foo/tsconfig.json`。
- 如果父目录中的 `deno.json` 含有 `compilerOptions`,则优先于任何 TSConfig。
支持以下字段:
```json title="tsconfig.json"
{
"extends": "...",
"files": ["..."],
"include": ["..."],
"exclude": ["..."],
"references": [
{ "path": "..." }
],
"compilerOptions": {
"...": "..."
}
}
```
除 `compilerOptions` 外,这些字段不能在 `deno.json` 中指定。
您可能在某些情况下被迫使用 `tsconfig.json`,例如当 [`include`](https://www.typescriptlang.org/tsconfig/#include) 所需的粒度无法通过 `deno.json` 工作区和目录作用域表示时。
## TS 编译器选项
以下是可更改的编译器选项列表,包括它们在 Deno 中的默认值和相关说明:
| 选项 | 默认值 | 备注 |
| ------------------------------ | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `allowUnreachableCode` | `false` | |
| `allowUnusedLabels` | `false` | |
| `baseUrl` | `"./"` | 用于解析 `paths` 和 `rootDirs` 中的裸模块描述符,但不会用于模块导入中的裸描述符。 |
| `checkJs` | `false` | |
| `jsx` | `"react"` | |
| `jsxFactory` | `"React.createElement"`| |
| `jsxFragmentFactory` | `"React.Fragment"` | |
| `keyofStringsOnly` | `false` | |
| `lib` | `[ "deno.window" ]` | 该选项的默认值根据 Deno 中的其他设置而异。若提供此选项,则会覆盖默认设置。详见下文。 |
| `module` | `"nodenext"` | 支持的值包括:`["nodenext", "esnext", "preserve"]`。 |
| `moduleResolution` | `"nodenext"` | 支持的值包括:`["nodenext", "bundler"]`。 |
| `noErrorTruncation` | `false` | |
| `noFallthroughCasesInSwitch` | `false` | |
| `noImplicitAny` | `true` | |
| `noImplicitOverride` | `true` | |
| `noImplicitReturns` | `false` | |
| `noImplicitThis` | `true` | |
| `noImplicitUseStrict` | `true` | |
| `noStrictGenericChecks` | `false` | |
| `noUncheckedIndexedAccess` | `false` | |
| `noUnusedLocals` | `false` | |
| `noUnusedParameters` | `false` | |
| `paths` | `{}` | |
| `rootDirs` | `null` | |
| `strict` | `true` | |
| `strictBindCallApply` | `true` | |
| `strictFunctionTypes` | `true` | |
| `strictPropertyInitialization`| `true` | |
| `strictNullChecks` | `true` | |
| `suppressExcessPropertyErrors`| `false` | |
| `suppressImplicitAnyIndexErrors` | `false` | |
| `useUnknownInCatchVariables` | `true` | |
有关完整编译器选项及其对 TypeScript 的影响,请参阅[TypeScript 手册](https://www.typescriptlang.org/docs/handbook/compiler-options.html)。
## 使用 "lib" 属性
如果您的项目需要向多个运行时(例如浏览器)发送代码,您可以通过 `compilerOptions` 中的 "lib" 属性调整默认类型。
常用内置库说明:
- `"deno.ns"` — 包含所有自定义的 `Deno` 全局命名空间 API 以及 Deno 对 `import.meta` 的扩展。通常不会与其他库或全局类型冲突。
- `"deno.unstable"` — 包含额外的不稳定 `Deno` 全局命名空间 API。
- `"deno.window"` — 这是检查 Deno 主运行时脚本时使用的“默认”库,包含 `"deno.ns"` 以及内置扩展的其他类型库。此库会与标准 TypeScript 库(如 `"dom"` 和 `"dom.iterable"`)冲突。
- `"deno.worker"` — 检查 Deno 网络工作者脚本时使用的库。更多信息见[Web 工作者的类型检查](/runtime/reference/ts_config_migration/#type-checking-web-workers)。
- `"dom.asynciterable"` — TypeScript 当前不包含 Deno 实现的 DOM 异步可迭代对象(以及多个浏览器均支持),因此我们自行实现,直至 TypeScript 支持该特性。
以下公共库默认不启用,但当编写计划在多种运行时正常工作的代码时非常有用:
- `"dom"` — TypeScript 的主要浏览器全局库。该类型定义与 `"deno.window"` 在多方面冲突,若使用 `"dom"`,建议只利用 `"deno.ns"` 公开 Deno 特定 API。
- `"dom.iterable"` — 浏览器全局库的可迭代扩展。
- `"scripthost"` — Microsoft Windows 脚本主机的库。
- `"webworker"` — 浏览器中 Web 工作者的主要库,类似 `"dom"`,它会与 `"deno.window"` 或 `"deno.worker"` 冲突,因此建议只使用 `"deno.ns"`。
- `"webworker.importscripts"` — Web 工作者中可用的 `importScripts()` API 库。
- `"webworker.iterable"` — 为 Web 工作者中的对象添加可迭代性,该特性受现代浏览器支持。
## 针对 Deno 和浏览器
若您希望编写可无缝运行于 Deno 和浏览器的代码,需在使用某环境独占的 API 之前条件性检查执行环境。典型的 `compilerOptions` 配置示例如下:
```json title="deno.json"
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "dom.asynciterable", "deno.ns"]
}
}
```
这应允许大多数代码在 Deno 中被正确类型检查。
如果您预计会在启用 `--unstable` 标志的 Deno 中运行代码,还应将该库添加:
```json title="deno.json"
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"dom.asynciterable",
"deno.ns",
"deno.unstable"
]
}
}
```
常见情况下,使用 TypeScript 的 `"lib"` 选项时还需包含对应的 "es" 库。而 `"deno.ns"` 和 `"deno.unstable"` 在引入时会自动包含 `"esnext"`。
:::note
如果您遇到类型错误,如 **找不到 `document` 或 `HTMLElement`**,可能是因为所用库依赖 DOM。这在设计为可运行于浏览器和服务器端的包中很常见。默认情况下,Deno 仅包含直接支持的库。假设包正确识别其运行时环境,类型检查时包含 DOM 库是“安全”的。
:::
## 类型和类型声明
Deno 采用 _无非标准模块解析_ 设计原则。TypeScript 检查文件时只关心其类型;相比之下,`tsc` 通过复杂逻辑解析类型。默认情况下,`tsc` 期望模块带有扩展名(如 `.ts`、`.d.ts`、`.js` 等)。而 Deno 处理的模块描述符均为明确带扩展名。
对于想使用已转译为 JavaScript 的 TypeScript 文件及其类型声明文件(例如 `mod.js` 和 `mod.d.ts`),Deno 会严格根据引入的请求加载 JavaScript 文件,但由于 TypeScript 还会考虑类型声明,Deno 的类型检查可能不如 TypeScript 完整。
为解决此问题,Deno 提供了两种解决方案,分别适用于不同场景:
**作为导入者:** 若您知道应应用于 JavaScript 模块的类型,可通过显式指定类型提示增强类型检查。
**作为提供者:** 若您是模块源代码或它的托管方,能够让使用此模块的人无需担心类型解析,享受类型服务。
## 导入时提供类型
当使用 JavaScript 模块,且已创建对应的类型定义(`.d.ts` 文件)或其他类型时,可以使用 `@ts-types` 注释指令指明类型文件:
```ts
// @ts-types="./coolLib.d.ts"
import * as coolLib from "./coolLib.js";
```
在此文件中使用 `coolLib` 时,`coolLib.d.ts` 中的 TypeScript 类型定义将优先于观察 JavaScript 文件。
:::note
历史上,`@ts-types` 指令曾称为 `@deno-types`。该别名仍有效,但不推荐使用。请使用 `@ts-types`。
:::
## 托管时提供类型
若您控制模块源代码或其在 Web 服务器上的托管方式,可通过两种方式告知 Deno 指定模块的类型(无需导入者额外操作)。
### @ts-self-types
若您提供 JavaScript 文件,且希望附带声明文件,可在 JS 文件中用 `@ts-self-types` 注释指明声明文件:
```js title="coolLib.js"
// @ts-self-types="./coolLib.d.ts"
// ... JavaScript 代码 ...
```
### X-TypeScript-Types 头部
Deno 支持远程模块响应头,指明该模块类型定义所在位置。例如,`https://example.com/coolLib.js` 的响应头:
```console
HTTP/1.1 200 OK
Content-Type: application/javascript; charset=UTF-8
Content-Length: 648
X-TypeScript-Types: ./coolLib.d.ts
```
Deno 在看到此头部时,会尝试加载 `https://example.com/coolLib.d.ts` 并在类型检查原始模块时使用它。
## 使用环境或全局类型
一般建议在 Deno 中使用模块化或 UMD 类型定义,即模块显式导入其所依赖类型。模块化类型定义可以通过类型定义中的 `declare global` 表达对[全局作用域的增强](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-modifying-module-d-ts.html),例如:
```ts
declare global {
var AGlobalString: string;
}
```
此举使得在导入类型定义后 `AGlobalString` 可在全局命名空间访问。
在某些情况下,使用第三方类型库时无法采用模块化类型定义。为此,类型检查程序提供以下包含任意类型定义的方法。
### 三斜杠指令
通过在 TS 文件(非 JS!)顶部添加三斜杠的 `types` 指令,将类型定义与代码关联,令类型检查包含该定义,例如:
```ts
///
```
该引用的描述符与 Deno 中其他描述符一致解析,需带扩展名,且相对于引用模块。也可使用完整 URL:
```ts
///
```
### 在 deno.json 中提供 "types"
另一种方式是在 `deno.json` 的 `"compilerOptions"` 中指定 `"types"` 数组,例如:
```json title="deno.json"
{
"compilerOptions": {
"types": [
"./types.d.ts",
"https://deno.land/x/pkg@1.0.0/types.d.ts",
"/Users/me/pkg/types.d.ts"
]
}
}
```
这些类型描述符与三斜杠引用类似,按 Deno 规范解析;相对地址相对于配置文件位置。运行时传递 `--config=path/to/file`,确保 Deno 使用该配置。
## 对 Web 工作者进行类型检查
Deno 在加载 Web 工作者中的 TypeScript 模块时,会自动对模块及其依赖项使用网络工作者相关库类型检查。这可能在其他环境(如使用 `deno check` 或编辑器中)造成挑战。您可通过以下方式向 Deno 指定使用网络工作者库,而非标准 Deno 库。
### 三斜杠指令
通过在工作者入口脚本顶部添加三斜杠库指令,将库设置与代码关联,例如:
```ts
///
///
```
第一条指令禁止使用默认库,避免冲突;第二条指令告知使用内置 Deno 网络工作者类型定义及依赖(如 `"esnext"`)。
此方案缺点是代码在非 Deno 平台(如 `tsc`)上可移植性差,因为 `"deno.worker"` 是 Deno 独有的库。
### 在 deno.json 中提供 "lib" 设置
您也可在 `deno.json` 中为 `"compilerOptions"` 指定 `"lib"`,如:
```json title="deno.json"
{
"compilerOptions": {
"target": "esnext",
"lib": ["deno.worker"]
}
}
```
运行相关命令时需传递 `--config path/to/file`,或在支持 Deno 语言服务器的 IDE 中设置 `deno.config`。
如果项目兼含非工作者脚本,请相应决定是否省略 `--config` 参数或配置适用于非工作者模块的配置文件。
## 重要事项
### 类型声明语义
类型声明文件(`.d.ts`)遵循与 Deno 其他文件相同的语义,即默认为模块声明(_UMD 声明_),非环境或全局声明。Deno 对环境/全局声明的处理不可预测。
此外,若类型声明文件导入其他模块(例如另一个 `.d.ts` 文件),其解析遵循 Deno 的正常导入规则。许多生成的并在线可得的 `.d.ts` 文件可能与 Deno 不兼容。
[esm.sh](https://esm.sh) 是一个默认提供类型声明的 CDN(通过 `X-TypeScript-Types` 头部)。可通过在导入 URL 后加 `?no-dts` 参数禁用,例如:
```ts
import React from "https://esm.sh/react?no-dts";
```
## JavaScript 在类型检查时的表现
当在 Deno 中将 JavaScript 代码导入 TypeScript 时,即使 `checkJs` 设置为 `false`(Deno 默认),TypeScript 编译器仍会分析 JavaScript 模块,尝试推断模块导出形状,以验证 TypeScript 文件中的导入有效性。
通常情况下,导入标准 ES 模块不会有问题。但在某些场景(如特殊打包方式或全局 UMD 模块)下,这种分析可能失败。遇到此类情况,最好采用前述的类型提示方案。
### 内部工作原理
虽然理解 Deno 内部机制非使用 TypeScript 和 Deno 的必要,但有助于理解其运作。
Deno 在执行或编译代码前,首先解析根模块生成模块图,检测所有依赖并递归获取和解析直到完整。
针对每个依赖,存在两个“槽”:代码槽和类型槽。填充模块图时,若模块为可发射成 JavaScript 的内容,填充代码槽;类型依赖(如 `.d.ts` 文件)填充类型槽。
构建模块图并进行类型检查时,Deno 启动 TypeScript 编译器,将需要作为 JavaScript 发射的模块名提供给它。TypeScript 编译器请求额外模块时,Deno 会优先提供类型槽,再提供代码槽。
这意味着,导入 `.d.ts` 模块或采用前述解决方案为 JavaScript 代码提供替代类型模块时,TypeScript 获得的即为类型模块,而非解析时的代码模块。