deno.com
在当前页面

配置 TypeScript

Deno 的灵活性体现在它对 TypeScript 和 JavaScript 的平等对待上。无论你是从 JavaScript 过渡到 TypeScript,还是反之,Deno 都有功能来简化这一过程。

类型检查 JavaScript Jump to heading

你可能希望在不添加类型注解的情况下使你的 JavaScript 更具类型安全性。Deno 支持使用 TypeScript 类型检查器来检查 JavaScript 的类型。你可以通过在文件中添加检查 JavaScript 的编译指示来标记单个文件:

// @ts-check

这将使类型检查器推断出 JavaScript 代码的类型信息,并将任何问题作为诊断问题提出。

通过提供一个配置文件并将 check JS 选项设置为 true,可以为程序中的所有 JavaScript 文件启用这些功能,如下所示。然后在命令行运行时使用 --config 选项。

{
  "compilerOptions": {
    "checkJs": true
  }
}

在 JavaScript 中使用 JSDoc Jump to heading

当对 JavaScript 进行类型检查或将 JavaScript 导入 TypeScript 时,JSDoc 注解可以提供超出代码本身所能推断的额外类型信息。如果你在代码中内联使用支持的 TypeScript JSDoc 进行注解,Deno 可以无缝支持这一点。

例如,要设置数组的类型,请使用以下 JSDoc 注释:

/** @type {string[]} */
const a = [];

跳过类型检查 Jump to heading

你可能有一些正在实验的 TypeScript 代码,其语法有效但并非完全类型安全。你可以通过传递 --no-check 标志来绕过整个程序的类型检查。

你也可以使用 nocheck 编译指示来跳过整个文件的类型检查,包括启用了 check JS 的 JavaScript:

// @ts-nocheck

将 JS 文件重命名为 TS 文件 Jump to heading

TypeScript 文件受益于 TypeScript 编译器能够对你的代码进行更彻底的安全检查。这通常被称为 严格模式。当你将 .js 文件重命名为 .ts 时,你可能会看到 TypeScript 之前无法检测到的新类型错误。

在 Deno 中配置 TypeScript Jump to heading

TypeScript 提供了许多配置选项,如果你刚开始使用 TS,这可能会让人望而生畏。Deno 旨在简化 TypeScript 的使用,而不是让你淹没在无数的设置中。Deno 将 TypeScript 配置为 开箱即用。无需额外的配置麻烦!

但是,如果你确实想更改 TypeScript 编译器选项,Deno 允许你在 deno.json 文件中进行更改。在命令行中提供路径,或使用默认路径。例如:

deno run --config ./deno.json main.ts

Note

如果你正在创建需要配置文件的库,请记住,所有使用你的 TS 模块的消费者也需要该配置文件。此外,配置文件中可能存在使其他 TypeScript 模块不兼容的设置。

TS 编译器选项 Jump to heading

以下是可更改的编译器选项表,它们在 Deno 中的默认值以及有关该选项的其他说明:

选项 默认值 说明
allowJs true 几乎不需要更改
allowUnreachableCode false
allowUnusedLabels false
checkJs false 如果为 true,则 TypeScript 会检查 JavaScript 的类型
jsx "react"
jsxFactory "React.createElement"
jsxFragmentFactory "React.Fragment"
keyofStringsOnly false
lib [ "deno.window" ] 此默认值根据 Deno 中的其他设置而变化。如果提供了该值,它将覆盖默认值。有关更多信息,请参见下文。
noErrorTruncation false
noFallthroughCasesInSwitch false
noImplicitAny true
noImplicitOverride true
noImplicitReturns false
noImplicitThis true
noImplicitUseStrict true
noStrictGenericChecks false
noUnusedLocals false
noUnusedParameters false
noUncheckedIndexedAccess false
reactNamespace React
strict true
strictBindCallApply true
strictFunctionTypes true
strictPropertyInitialization true
strictNullChecks true
suppressExcessPropertyErrors false
suppressImplicitAnyIndexErrors false
useUnknownInCatchVariables true

有关编译器选项的完整列表及其对 TypeScript 的影响,请参阅 TypeScript 手册

使用 "lib" 属性 Jump to heading

如果你正在开发一个将代码发布到多个运行时的项目,例如浏览器,你可以通过 compilerOptions 中的 "lib" 属性调整默认类型。

用户感兴趣的内置库:

  • "deno.ns" - 这包括所有自定义的 Deno 全局命名空间 API 以及 Deno 对 import.meta 的添加。这通常不会与其他库或全局类型冲突。
  • "deno.unstable" - 这包括额外的不稳定 Deno 全局命名空间 API。
  • "deno.window" - 这是检查 Deno 主运行时脚本时使用的 "默认" 库。它包括 "deno.ns" 以及 Deno 内置扩展的其他类型库。此库将与 "dom""dom.iterable" 等标准 TypeScript 库冲突。
  • "deno.worker" - 这是检查 Deno Web Worker 脚本时使用的库。有关 Web Worker 的更多信息,请参阅 类型检查 Web Worker
  • "dom.asynciterable" - TypeScript 目前不包括 Deno 实现的 DOM 异步可迭代对象(以及几个浏览器),因此我们自己实现了它,直到它在 TypeScript 中可用。

这些是默认情况下未启用的常见库,但在编写旨在在其他运行时中工作的代码时很有用:

  • "dom" - TypeScript 附带的主要浏览器全局库。类型定义在许多方面与 "deno.window" 冲突,因此如果使用 "dom",则考虑仅使用 "deno.ns" 来暴露 Deno 特定的 API。
  • "dom.iterable" - 浏览器全局库的可迭代扩展。
  • "scripthost" - Microsoft Windows Script Host 的库。
  • "webworker" - 浏览器中 Web Worker 的主要库。与 "dom" 一样,这将与 "deno.window""deno.worker" 冲突,因此考虑仅使用 "deno.ns" 来暴露 Deno 特定的 API。
  • "webworker.importscripts" - 暴露 Web Worker 中 importScripts() API 的库。
  • "webworker.iterable" - 向 Web Worker 中的对象添加可迭代对象的库。现代浏览器支持这一点。

针对 Deno 和浏览器 Jump to heading

你可能希望编写在 Deno 和浏览器中无缝运行的代码。在这种情况下,你需要在执行任何特定于其中一个或另一个的 API 之前有条件地检查执行环境。在这种情况下,典型的 compilerOptions 配置可能如下所示:

deno.json
{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "dom.asynciterable", "deno.ns"]
  }
}

这应该允许 Deno 正确地对大多数代码进行类型检查。

如果你希望在 Deno 中使用 --unstable 标志运行代码,那么你还应该将该库添加到混合中:

deno.json
{
  "compilerOptions": {
    "lib": [
      "dom",
      "dom.iterable",
      "dom.asynciterable",
      "deno.ns",
      "deno.unstable"
    ]
  }
}

通常,当你在 TypeScript 中使用 "lib" 选项时,你还需要包含一个 "es" 库。在 "deno.ns""deno.unstable" 的情况下,当你引入它们时,它们会自动包含 "esnext"

Note

如果你遇到类似 无法找到 documentHTMLElement 的类型错误,很可能你使用的库依赖于 DOM。这对于设计为在浏览器和服务器端运行的包来说很常见。默认情况下,Deno 仅包括直接支持的库。假设包在运行时正确识别了它运行的环境,使用 DOM 库来类型检查代码是 "安全" 的。

类型和类型声明 Jump to heading

Deno 采用了 无非标准模块解析 的设计原则。当 TypeScript 检查文件时,它只关注其类型。相比之下,tsc 编译器采用复杂的逻辑来解析这些类型。默认情况下,tsc 期望带有扩展名的模糊模块说明符(例如 .ts.d.ts.js)。然而,Deno 处理的是明确的说明符。

有趣的是:假设你想使用一个已经编译为 JavaScript 的 TypeScript 文件及其类型定义文件(mod.jsmod.d.ts)。如果你将 mod.js 导入 Deno,它会严格遵循你的请求并导入 JavaScript 文件。但问题是:你的代码不会像 TypeScript 考虑 mod.d.ts 文件那样进行彻底的类型检查。

为了解决这个问题,Deno 提供了两种解决方案,每种方案都针对特定场景:

作为导入者: 如果你知道应该应用于 JavaScript 模块的类型,你可以通过明确指定类型来增强类型检查。

作为提供者: 如果你是模块的提供者或托管者,所有使用它的人都会受益,而无需担心类型解析。

导入时提供类型 Jump to heading

如果你正在使用一个 JavaScript 模块,并且你已经创建了类型(一个 .d.ts 文件)或以其他方式获得了你想要使用的类型,你可以使用 @ts-types 编译提示指示 Deno 在类型检查时使用该文件,而不是 JavaScript 文件。

例如,如果你有一个 JavaScript 模块 coolLib.js 和一个单独的 coolLib.d.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

托管时提供类型 Jump to heading

如果你控制模块的源代码或文件在 Web 服务器上的托管方式,有两种方法可以让 Deno 知道特定模块的类型(这不需要导入者采取任何特殊操作)。

@ts-self-types Jump to heading

如果你正在提供一个 JavaScript 文件,并且想提供一个包含该文件类型的声明文件,你可以在 JS 文件中指定一个 @ts-self-types 指令,指向声明文件。

例如,如果你制作了一个 coolLib.js 库,并在 coolLib.d.ts 中编写了其类型定义,ts-self-types 指令将如下所示:

coolLib.js
// @ts-self-types="./coolLib.d.ts"

// ... 其余的 JavaScript ...

X-TypeScript-Types Jump to heading

Deno 支持一个用于远程模块的标头,指示 Deno 在哪里找到给定模块的类型。例如,https://example.com/coolLib.js 的响应可能如下所示:

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 并在类型检查原始模块时使用它。

使用环境或全局类型 Jump to heading

总的来说,最好在 Deno 中使用模块/UMD 类型定义,其中模块明确导入它所依赖的类型。模块化类型定义可以通过 declare global 在类型定义中表达 全局范围的扩展。例如:

declare global {
  var AGlobalString: string;
}

这将使 AGlobalString 在导入类型定义时在全局命名空间中可用。

在某些情况下,当利用其他现有类型库时,可能无法利用模块化类型定义。因此,有一些方法可以在类型检查程序时包含任意类型定义。

三斜杠指令 Jump to heading

此选项将类型定义与代码本身耦合。通过在 TS 文件(而不是 JS 文件!)中添加三斜杠 types 指令,类型检查文件时将包含类型定义。例如:

/// <reference types="./types.d.ts" />

提供的说明符像 Deno 中的任何其他说明符一样解析,这意味着它需要一个扩展名,并且相对于引用它的模块。它也可以是一个完全限定的 URL:

/// <reference types="https://deno.land/x/pkg@1.0.0/types.d.ts" />

在 deno.json 中提供 "types" Jump to heading

另一个选项是在 deno.json 中的 "compilerOptions" 中提供 "types" 值。例如:

deno.json
{
  "compilerOptions": {
    "types": [
      "./types.d.ts",
      "https://deno.land/x/pkg@1.0.0/types.d.ts",
      "/Users/me/pkg/types.d.ts"
    ]
  }
}

与上面的三斜杠引用一样,"types" 数组中提供的说明符将像 Deno 中的其他说明符一样解析。在相对说明符的情况下,它将相对于配置文件的路径解析。确保通过指定 --config=path/to/file 标志告诉 Deno 使用此文件。

类型检查 Web Worker Jump to heading

当 Deno 在 Web Worker 中加载 TypeScript 模块时,它将自动根据 Deno Web Worker 库对模块及其依赖项进行类型检查。这在 deno check 或编辑器等其他上下文中可能会带来挑战。有几种方法可以指示 Deno 使用 Worker 库而不是标准 Deno 库。

三斜杠指令 Jump to heading

此选项将库设置与代码本身耦合。通过在 Worker 脚本的入口点文件顶部附近添加以下三斜杠指令,Deno 现在将将其作为 Deno Worker 脚本进行类型检查,无论模块如何分析:

/// <reference no-default-lib="true" />
/// <reference lib="deno.worker" />

第一个指令确保不使用其他默认库。如果省略这一点,你将得到一些冲突的类型定义,因为 Deno 将尝试应用标准 Deno 库。第二个指令指示 Deno 应用内置的 Deno Worker 类型定义以及依赖库(如 "esnext")。

这样做的一个缺点是,它使代码在其他非 Deno 平台(如 tsc)上的可移植性降低,因为只有 Deno 内置了 "deno.worker" 库。

在 deno.json 中提供 "lib" 设置 Jump to heading

你可以在 deno.json 文件中提供 "lib" 选项来指示 Deno 使用库文件。例如:

deno.json
{
  "compilerOptions": {
    "target": "esnext",
    "lib": ["deno.worker"]
  }
}

然后在运行 deno 子命令时,你需要传递 --config path/to/file 参数,或者如果你使用的是利用 Deno 语言服务器的 IDE,请设置 deno.config 设置。

如果你还有非 Worker 脚本,你将需要省略 --config 参数,或者有一个配置为满足非 Worker 脚本需求的配置文件。

重要点 Jump to heading

类型声明语义 Jump to heading

类型声明文件(.d.ts 文件)遵循与 Deno 中其他文件相同的语义。这意味着声明文件被假定为模块声明(UMD 声明),而不是环境/全局声明。Deno 如何处理环境/全局声明是不可预测的。

此外,如果类型声明导入了其他内容,如另一个 .d.ts 文件,其解析遵循 Deno 的正常导入规则。对于许多生成并可在网络上找到的 .d.ts 文件,它们可能与 Deno 不兼容。

esm.sh 是一个默认提供类型声明的 CDN(通过 X-TypeScript-Types 标头)。可以通过在导入 URL 后附加 ?no-dts 来禁用它:

import React from "https://esm.sh/react?no-dts";

类型检查时 JavaScript 的行为 Jump to heading

当你在 Deno 中将 JavaScript 代码导入 TypeScript 时,即使你将 checkJs 设置为 false(这是 Deno 的默认行为),TypeScript 编译器仍会分析

你找到需要的内容了吗?

隐私政策