---
title: "TypeScript 支持"
description: "了解如何在 Deno 中使用 TypeScript。涵盖配置选项、类型检查以及编写类型安全 Deno 应用的最佳实践。"
oldUrl:
- /runtime/manual/advanced/typescript/
- /runtime/manual/typescript/
- /runtime/manual/typescript/overview/
- /runtime/manual/getting_started/typescript/
- /manual/advanced/typescript
- /runtime/manual/advanced/typescript/overview/
- /runtime/fundamentals/
---
TypeScript 是 Deno 中的一种一流语言,就像 JavaScript 或 WebAssembly 一样。您只需安装 Deno CLI,就可以运行或导入 TypeScript,而无需安装其他任何东西。凭借其内置的 TypeScript 编译器,Deno 将直接把您的 TypeScript 代码编译为 JavaScript,无需额外配置。Deno 还可以对您的 TypeScript 代码进行类型检查,无需像 `tsc` 这样的单独类型检查工具。
## 类型检查
TypeScript 的主要优势之一是它可以使您的代码类型安全,捕获开发过程中而非运行时的错误。TypeScript 是 JavaScript 的超集,这意味着语法上有效的 JavaScript 会变成 TypeScript,并发出“安全性”警告。
:::note
**Deno 默认在 `strict mode` 下对 TypeScript 进行类型检查**,TypeScript 核心团队
[建议将严格模式作为合理的默认值](https://www.typescriptlang.org/play/?#example/new-compiler-defaults)。
:::
Deno 允许您使用 [`deno check`](/runtime/reference/cli/check/) 子命令对代码进行类型检查(而不执行它):
```shell
# 检查当前目录/模块
deno check
# 检查特定的 TypeScript 文件
deno check module.ts
# 在检查中包含远程模块和 npm 包
deno check --all module.ts
# 检查 JSDoc 注释中的代码片段
deno check --doc module.ts
# 检查 markdown 文件中的代码片段
deno check --doc-only markdown.md
```
:::note
类型检查可能会花费大量时间,尤其是在您对代码库进行大量更改时。Deno 优化了类型检查,但这仍然是有成本的。因此,**默认情况下,TypeScript 模块在执行之前不会进行类型检查**。
:::
在使用 `deno run` 命令时,Deno 将跳过类型检查并直接运行代码。如果您希望在执行代码之前对模块进行类型检查,可以使用 `--check` 标志与 `deno run` 一起使用:
```shell
deno run --check module.ts
# 也可以对远程模块和 npm 包进行类型检查
deno run --check=all module.ts
```
当 Deno 在使用此标志时遇到类型错误时,过程将在执行代码之前退出。
为了避免这种情况,您需要:
- 解决问题
- 使用 `// @ts-ignore` 或 `// @ts-expect-error` 指令来忽略错误
- 或者完全跳过类型检查
在测试您的代码时,类型检查默认是启用的。如果您希望跳过类型检查,可以使用 `--no-check` 标志:
```shell
deno test --no-check
```
## 与 JavaScript 一起使用
Deno 可以运行 JavaScript 和 TypeScript 代码。然而,在类型检查期间,Deno 默认只对 TypeScript 文件进行类型检查。如果您想对 JavaScript 文件进行类型检查,可以在文件顶部添加 `// @ts-check` 指令,或在 `deno.json` 文件中添加 `compilerOptions.checkJs`。
```ts title="main.js"
// @ts-check
let x = "hello";
x = 42; // 类型 'number' 不能赋值给类型 'string'。
```
```json title="deno.json"
{
"compilerOptions": {
"checkJs": true
}
}
```
在 JavaScript 文件中,您不能使用 TypeScript 语法,例如类型注解或导入类型。不过,您可以使用 [TSDoc](https://tsdoc.org/) 注释向 TypeScript 编译器提供类型信息。
```ts title="main.js"
// @ts-check
/**
* @param a {number}
* @param b {number}
* @returns {number}
*/
function add(a, b) {
return a + b;
}
```
## 提供声明文件
在从 TypeScript 代码导入未标注类型的 JavaScript 模块时,您可能需要为 JavaScript 模块提供类型信息。如果 JavaScript 使用 TSDoc 注释进行了注解,则不需要此操作。如果没有此额外的类型信息(以 `.d.ts` 声明文件的形式),TypeScript 将假定从 JavaScript 模块导出的所有内容都是 `any` 类型。
`tsc` 会自动识别与 `js` 文件同级且具有相同基本名称的 `d.ts` 文件。**Deno 并不这样做。**您必须在 `.js` 文件(源文件)或 `.ts` 文件(导入者)中显式指定 `.d.ts` 文件的位置。
### 在源文件中提供类型
在 `.js` 文件中指定 `.d.ts` 文件应该是首选,因为这样使得从多个 TypeScript 模块使用 JavaScript 模块变得更容易:您无需在每个导入 JavaScript 模块的 TypeScript 模块中指定 `.d.ts` 文件。
```ts title="add.js"
// @ts-self-types="./add.d.ts"
export function add(a, b) {
return a + b;
}
```
```ts title="add.d.ts"
export function add(a: number, b: number): number;
```
### 在导入者中提供类型
如果您无法修改 JavaScript 源代码,可以在导入 JavaScript 模块的 TypeScript 模块中指定 `.d.ts` 文件。
```ts title="main.ts"
// @ts-types="./add.d.ts"
import { add } from "./add.js";
```
这对于不提供类型信息的 NPM 包也很有用:
```ts title="main.ts"
// @ts-types="npm:@types/lodash"
import * as _ from "npm:lodash";
```
### 为 HTTP 模块提供类型
通过 HTTP 托管 JavaScript 模块的服务器也可以在 HTTP 头中提供这些模块的类型信息。Deno 将在对模块进行类型检查时使用此信息。
```http
HTTP/1.1 200 OK
Content-Type: application/javascript; charset=UTF-8
Content-Length: 648
X-TypeScript-Types: ./add.d.ts
```
`X-TypeScript-Types` 头指定提供 JavaScript 模块类型信息的 `.d.ts` 文件的位置。它是相对于 JavaScript 模块的 URL 进行解析的,类似于 `Location` 头。
## 浏览器和 web worker 的类型检查
默认情况下,Deno 对 TypeScript 模块进行类型检查,就好像它们在 Deno 运行时的主线程中运行一样。然而,Deno 还支持浏览器的类型检查、web worker 的类型检查,以及在使用 SSR(服务器端渲染)与 Deno 时结合的浏览器-Deno 环境的类型检查。
这些环境具有不同的全局对象和可用的 API。Deno 提供了这些环境的类型定义,形式为库文件。这些库文件由 TypeScript 编译器使用,以提供这些环境中可用的全局对象和 API 的类型信息。
通过 `deno.json` 配置文件中的 `compilerOptions.lib` 选项或通过 TypeScript 文件中的 `/// ` 注释,可以更改加载的库文件。建议使用 `deno.json` 配置文件中的 `compilerOptions.lib` 选项来指定要使用的库文件。
要启用对 **浏览器环境** 的类型检查,您可以在 `deno.json` 配置文件的 `compilerOptions.lib` 选项中指定 `dom` 库文件:
```json title="deno.json"
{
"compilerOptions": {
"lib": ["dom"]
}
}
```
这将启用对浏览器环境的类型检查,为全局对象(如 `document`)提供类型信息。但是,这将禁用 Deno 特定 API(如 `Deno.readFile`)的类型信息。
要启用对 **浏览器和 Deno 环境** 的组合类型检查,例如在使用 Deno 进行 SSR 时,您可以在 `deno.json` 配置文件的 `compilerOptions.lib` 选项中指定 `dom` 和 `deno.ns`(Deno 命名空间)库文件:
```json title="deno.json"
{
"compilerOptions": {
"lib": ["dom", "deno.ns"]
}
}
```
这将同时启用对浏览器和 Deno 环境的类型检查,为全局对象(如 `document`)和 Deno 特定 API(如 `Deno.readFile`)提供类型信息。
要启用对 **Deno 中 web worker 环境** 的类型检查(即用 `new Worker` 运行的代码),您可以在 `deno.json` 的 `compilerOptions.lib` 选项中指定 `deno.worker` 库文件:
```json title="deno.json"
{
"compilerOptions": {
"lib": ["deno.worker"]
}
}
```
要在 TypeScript 文件中指定要使用的库文件,您可以使用 `/// ` 注释:
```ts
///
///
```
## 扩展全局类型
Deno 支持 TypeScript 中的环境(ambient)或全局类型。当填充全局对象或用附加属性扩展全局作用域时,这非常有用。**您应该尽可能避免使用环境或全局类型**,因为它们会导致命名冲突,并使您更难理解代码。在发布到 JSR 时也不支持它们。
要在 Deno 中使用环境或全局类型,您可以使用 `declare global` 语法,或加载一个扩展了全局作用域的 `.d.ts` 文件。
### 使用 declare global 扩展全局作用域
您可以在项目中导入的任何 TypeScript 文件中使用 `declare global` 语法,以将附加属性扩展到全局作用域。例如:
```ts
declare global {
interface Window {
polyfilledAPI(): string;
}
}
```
这使得在导入类型定义时全局可用 `polyfilledAPI` 函数。
### 使用 .d.ts 文件扩展全局作用域
您还可以使用 `.d.ts` 文件扩展全局作用域。例如,您可以创建一个包含以下内容的 `global.d.ts` 文件:
```ts
interface Window {
polyfilledAPI(): string;
}
```
然后您可以在您的 TypeScript 中通过 `/// ` 加载此 `.d.ts` 文件。这将用 `polyfilledAPI` 函数扩展全局作用域。
或者,您可以在 `deno.json` 配置文件中的 `compilerOptions.types` 数组中指定 `.d.ts` 文件:
```json
{
"compilerOptions": {
"types": ["./global.d.ts"]
}
}
```
这也将用 `polyfilledAPI` 函数扩展全局作用域。