Deno 中的 TypeScript 概述
Deno 的优势之一是它将 TypeScript 视为一等公民语言,就像 JavaScript 或 WebAssembly 一样,在 Deno 中运行代码时。这意味着您可以在 Deno 中运行或导入 TypeScript,而无需安装任何其他内容,除了 Deno CLI。
等等,Deno 真的运行 TypeScript 吗?您可能会问自己。嗯,这取决于你对“运行”的定义。有人可能会说,在浏览器中,您实际上并没有运行 JavaScript。浏览器中的 JavaScript 引擎将 JavaScript 转换为一系列操作码,然后在沙箱中执行这些操作码。因此它将 JavaScript 转换为类似于汇编的东西。即使 WebAssembly 也经过类似的转换,因为 WebAssembly 是与架构无关的,而它需要被转换为特定平台架构所需的机器特定操作码。因此,当我们说 TypeScript 是 Deno 中的一等公民语言时,我们的意思是,我们试图使 TypeScript 的编写和运行体验与 JavaScript 和 WebAssembly 一样简单直观。
在幕后,我们使用 Rust 和 JavaScript 中的一系列技术来提供这种体验。
它是如何工作的? 跳转到标题
在高层次上,Deno 将 TypeScript(以及 TSX 和 JSX)转换为 JavaScript。它通过结合 TypeScript 编译器(我们将其构建到 Deno 中)和一个名为 swc 的 Rust 库来实现。当代码经过类型检查和转换后,它将存储在缓存中,准备在下一次运行时使用,无需再次将其从源代码转换为 JavaScript。
您可以通过运行 deno info
来查看此缓存位置。
> deno info
DENO_DIR location: "/path/to/cache/deno"
Remote modules cache: "/path/to/cache/deno/deps"
TypeScript compiler cache: "/path/to/cache/deno/gen"
如果您查看该缓存,您将看到一个目录结构,它模仿源目录结构,以及单独的 .js
和 .meta
文件(也可能包含 .map
文件)。.js
文件是转换后的源文件,而 .meta
文件包含我们想要缓存的有关该文件元数据,目前包含源模块的哈希,这有助于我们管理缓存失效。您可能还会看到一个 .buildinfo
文件,它是一个 TypeScript 编译器增量构建信息文件,我们将其缓存以帮助加快类型检查速度。
类型检查 跳转到标题
TypeScript 的主要优势之一是您可以使代码更类型安全,因此,在语法上有效的 JavaScript 将成为带有“不安全”警告的 TypeScript。
您可以使用以下命令对代码进行类型检查(而不执行它)
deno check module.ts
# or also type check remote modules and npm packages
deno check --all module.ts
类型检查可能需要大量时间,尤其是在您正在处理一个代码库,并且您正在进行大量更改的情况下。我们已经尝试优化类型检查,但它仍然需要付出代价。因此,默认情况下,TypeScript 模块在执行之前不会进行类型检查。
deno run module.ts
当使用上面的命令时,Deno 只会在执行之前转译模块,忽略任何潜在的类型相关问题。为了在执行发生之前对模块进行类型检查,必须将 --check
参数与 deno run
一起使用。
deno run --check module.ts
# or also type check remote modules and npm packages
deno run --check=all module.ts
虽然 tsc
将(默认情况下)在遇到诊断(类型检查)问题时仍然发出 JavaScript,但 Deno 目前将其视为终止。当使用 deno run
以及 --check
参数时,类型相关的诊断将阻止程序运行:它将在这些警告上停止,并在执行代码之前退出进程。
为了避免这种情况,您需要解决问题,使用 // @ts-ignore
或 // @ts-expect-error
标记,或者完全跳过类型检查。
您可以了解更多关于类型检查参数的信息 这里。
确定文件类型 跳转到标题
由于 Deno 支持 JavaScript、TypeScript、JSX、TSX 模块,因此 Deno 必须决定如何处理这些类型的文件。对于本地模块,Deno 根据扩展名来确定。当本地文件没有扩展名时,它被认为是 JavaScript。可以使用 --ext
参数覆盖模块类型。这在模块没有文件扩展名时很有用,例如,因为它嵌入在另一个文件中。
对于远程模块,使用媒体类型(mime 类型)来确定模块类型,其中模块的路径用于帮助影响文件类型,当文件类型不明确时。
例如,.d.ts
文件和 .ts
文件在 TypeScript 中具有不同的语义,并且在 Deno 中需要以不同的方式处理。虽然我们希望将 .ts
文件转换为 JavaScript,但 .d.ts
文件不包含任何“可运行”代码,它只是描述类型(通常是“普通”JavaScript)。因此,当我们获取远程模块时,.ts.
和 .d.ts
文件的媒体类型看起来相同。因此,我们查看路径,如果我们看到以 .d.ts
结尾的路径,我们将它视为仅类型定义文件,而不是“可运行”TypeScript。
支持的媒体类型 跳转到标题
下表列出了 Deno 在识别远程模块文件类型时支持的媒体类型
媒体类型 | 文件处理方式 |
---|---|
application/typescript |
TypeScript(受路径扩展名影响) |
text/typescript |
TypeScript(受路径扩展名影响) |
video/vnd.dlna.mpeg-tts |
TypeScript(受路径扩展名影响) |
video/mp2t |
TypeScript(受路径扩展名影响) |
application/x-typescript |
TypeScript(受路径扩展名影响) |
application/javascript |
JavaScript(受路径扩展名影响) |
text/javascript |
JavaScript(受路径扩展名影响) |
application/ecmascript |
JavaScript(受路径扩展名影响) |
text/ecmascript |
JavaScript(受路径扩展名影响) |
application/x-javascript |
JavaScript(受路径扩展名影响) |
application/node |
JavaScript(受路径扩展名影响) |
text/jsx |
JSX |
text/tsx |
TSX |
text/plain |
尝试确定路径扩展名,否则未知 |
application/octet-stream |
尝试确定路径扩展名,否则未知 |
默认情况下严格 跳转到标题
Deno 默认情况下以严格模式对 TypeScript 进行类型检查,TypeScript 核心团队建议严格模式作为合理的默认值。此模式通常启用 TypeScript 的功能,这些功能可能应该从一开始就存在,但随着 TypeScript 的不断发展,对于现有代码来说将是重大更改。
混合 JavaScript 和 TypeScript 跳转到标题
默认情况下,Deno 不会对 JavaScript 进行类型检查。这可以更改,并在 在 Deno 中配置 TypeScript 中进一步讨论。Deno 支持 JavaScript 导入 TypeScript 和 TypeScript 导入 JavaScript,在复杂场景中。
但需要注意的是,在对 TypeScript 进行类型检查时,Deno 默认情况下会“读取”所有 JavaScript,以便能够评估它可能对 TypeScript 类型的影响。类型检查器将尽力弄清楚您导入到 TypeScript 中的 JavaScript 的类型,包括读取任何 JSDoc 注释。这方面的详细信息在 类型和类型声明 部分中详细讨论。
类型解析 跳转到标题
Deno 的核心设计原则之一是避免非标准模块解析,这也适用于类型解析。如果您想使用具有类型定义的 JavaScript(例如 .d.ts
文件),您必须明确告诉 Deno 关于这一点。如何实现这一点的详细信息在 类型和类型声明 部分中介绍。