

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# AL2023 中的 TypeScript
<a name="typescript"></a>

**注意**  
 本文档提供了关于 TypeScript 及其基于 Node.js 的执行环境的基本信息。它还涵盖了典型的开发工作流程，并解释了 TypeScript 如何打包在 AL2023 中以提供一致且可复现的开发环境。

 [https://www.typescriptlang.org/](https://www.typescriptlang.org/)（TS）是一种基于 JavaScript（JS）的编程语言，它提供 JS 的所有功能，并且还[通过类型系统对其进行了扩展](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)。在典型场景中，用 TS 编写的程序首先被翻译成 JS 代码，然后像任何其他常规 JS 程序一样由 Node.js 执行。在 TS 的特定术语中，此翻译过程被称为[编译，并由称为 *tsc* 的编译器执行](https://www.typescriptlang.org/docs/handbook/typescript-tooling-in-5-minutes.html)。*tsc* 编译器本身是用 JS 编写的，因此要运行它，也需要一个 JS 运行时环境，例如 Node.js。与其他一些 JS 运行时环境不同，Node.js 目前仅提供实验性和轻量级的 TS 支持。完整的 TS 支持，包括类型检查，仍然需要使用第三方程序包，例如 [typescript](https://www.npmjs.com/package/typescript)。获取 Node.js 运行时环境的 *tsc*（TS 编译器）的预期方式是安装 typescript node 模块。这可以使用程序包管理器之一来完成，通常是 *npm*。使用 *npm* 安装 TS 编译器有两种方式：全局安装和在项目中安装。[官方推荐的方法是基于每个项目安装](https://www.typescriptlang.org/download/) TS 编译器，这确保了项目的长期一致性和可复现性。然而，全局安装 TS 编译器可能仍然有用，因为它为整个主机及其 JS 运行时提供相同的版本，从而适用于本地未安装 TS 编译器的项目。这正是 Amazon Linux 上可用的 RPM 程序包（例如 `nodejs20-typescript` 或 `nodejs22-typescript`）安装 TS 编译器的方式：在系统级别全局安装，并为每个受支持的 Node.js 版本单独安装。

 *tsc* 不直接依赖于任何 Node.js 版本。编译器期望一定级别的运行时功能，这些功能通过选项（如 [target](https://www.typescriptlang.org/tsconfig/#target) 和 [lib](https://www.typescriptlang.org/tsconfig/#lib)）在特殊文件（*tsconfig.json*）中定义。这些选项的值代表 [ECMAScript](https://en.wikipedia.org/wiki/ECMAScript_version_history)（ES）标准的一个版本，该版本可能（或可能不）被 JS 运行时环境支持。不同版本的 Node.js 支持不同版本的 ES 标准。Node.js 的版本越新，支持的 ES 标准版本越高且越完整。如果项目的根目录中不存在 *tsconfig.json*，则将使用默认的配置选项集。不同版本 Node.js 的兼容性表以及各种 ES 标准版本的支持特性可在 [node.green](https://node.green/) 找到。*tsc* 有超过 100 个不同的选项，这些选项可以在 *tsconfig.json* 中定义。还支持配置链，即某些配置选项在另一个文件中定义，然后包含在主文件中。这种方法允许安装与特定版本 Node.js 兼容的[基础 TS 配置](https://github.com/tsconfig/bases)，然后使用项目特定选项进行扩展。幸运的是，适用于 Node.js 的基础 TS 配置可作为 node 模块使用，可以使用 *npm* 将其安装在项目文件夹中。这是适用于 Node.js 版本 [18](https://github.com/tsconfig/bases/blob/main/bases/node18.json)、[20](https://github.com/tsconfig/bases/blob/main/bases/node20.json) 和 [22](https://github.com/tsconfig/bases/blob/main/bases/node22.json) 的配置源代码。

 基于 Node.js 的运行时设计存在一个弱点：它在一台主机上仅支持一个运行时版本，并且要求在项目级别所有依赖项具有可复现性和一致性。这导致了以下使用 TypeScript 的常见方法：TS 编译器、当前 Node.js 版本的 TS 基础配置以及所有软件依赖项都在项目内部本地安装。虽然全局安装的 node 模块预期仅为 CLI 工具，例如 *npm*，但同样作为 CLI 工具的 *tsc* 却很少被全局安装。值得庆幸的是，*tsc* 的全局（系统范围内）和本地（项目内）安装可以毫无问题地共存，并且可以是独立使用的不同版本。请注意，本地安装的 *tsc* 应使用与 *npm* 一起安装的 *npx* 工具来执行。因此，即使有系统 TS 编译器，用户也有机会选择运行时组件的版本，例如 Node.js（通过 alternatives 切换活动版本）、TS 编译器（通过本地安装，或者全局安装并通过 alternatives 切换活动版本），并根据特定需求对其进行配置。

 Amazon Linux 打包 TS 编译器的方式与其他全局安装的 node 模块（例如 *npm*）相同，基于每个 Node.js 版本进行。程序包和二进制文件均采用命名空间组织方式，并且在其名称中包含 Node.js 的主版本号。编译器的默认可执行文件名称 *tsc* 在运行时由 alternatives 工具管理，并指向当前活动的、为其安装并将由其执行的 Node.js 版本。此选择不依赖于当前的 Node.js 运行时版本。可能会出现 *node* 可执行文件指向 Node.js 20，而 *tsc* 被配置为由 Node.js 22 解释的情况。也可以使用 TS 编译器的命名空间名称，例如 *tsc-\$1MAJOR\$1VERSION\$1*，这与默认的 *tsc* 名称配置为何无关。

**用于管理 TS 编译器活动版本的一些有用命令**

1. 检查 *alternatives* 的配置内容

   ```
   alternatives --list
   ```

1. 检查 *tsc* 的当前配置

   ```
   alternatives --display tsc
   ```

1. 交互式更改 tsc 版本

   ```
   alternatives --config tsc
   ```

1. 切换到手动模式并选择特定版本

   ```
   alternatives --set tsc /usr/bin/tsc-{MAJOR_VERSION}
   ```

1. 切换回自动版本选择模式

   ```
   alternatives --auto tsc
   ```

 在同一系统上安装和使用多个 Node 版本及 TS 编译器的示例：

```
# Check the AL2023 release
$ cat /etc/amazon-linux-release
Amazon Linux release 2023.9.20250929 (Amazon Linux)

# Install a TypeScript compiler for Node.js 20 and 22
# Node.js 20 and 22 will be installed automatically
$ sudo dnf install -qy nodejs20-typescript nodejs22-typescript

# Check what was installed
$ rpm -q nodejs20 nodejs20-typescript nodejs22 nodejs22-typescript
nodejs20-20.19.5-1.amzn2023.0.1.x86_64
nodejs20-typescript-5.9.2-1.amzn2023.0.1.noarch
nodejs22-22.19.0-1.amzn2023.0.1.x86_64
nodejs22-typescript-5.9.2-1.amzn2023.0.1.noarch

# Check the active version of Node.js - it is version 20
$ alternatives --display node
node - status is auto.
 link currently points to /usr/bin/node-20
/usr/bin/node-20 - priority 100
 slave npmrc: /usr/lib/nodejs20/lib/node_modules/npm/npmrc
 slave npm: /usr/bin/npm-20
 slave npx: /usr/bin/npx-20
 slave node_modules: /usr/lib/nodejs20/lib/node_modules
/usr/bin/node-22 - priority 100
 slave npmrc: /usr/lib/nodejs22/lib/node_modules/npm/npmrc
 slave npm: /usr/bin/npm-22
 slave npx: /usr/bin/npx-22
 slave node_modules: /usr/lib/nodejs22/lib/node_modules
Current 'best' version is /usr/bin/node-20.

# Check the active JS runtime version for TypeScript
# Currently, the tsc compiler will be executed by Node.js 22
$ alternatives --display tsc
tsc - status is auto.
 link currently points to /usr/bin/tsc-22
/usr/bin/tsc-22 - priority 100
 slave tsserver: /usr/bin/tsserver-22
/usr/bin/tsc-20 - priority 100
 slave tsserver: /usr/bin/tsserver-20
Current 'best' version is /usr/bin/tsc-22.

# Check versions printed by executables
$ node -v
v20.19.5

$ tsc -v
Version 5.9.2

# while the node is 20, tsc is executed by node 22 anyway
$ head -1 /usr/bin/tsc
#!/usr/bin/node-22

# However, instead of default executable names, e.g. node or tsc,
# we can use namespaced names to target any installed version
$ node-20 -v
v20.19.5

$ node-22 -v
v22.19.0

$ tsc-20 -v
Version 5.9.2

$ tsc-22 -v
Version 5.9.2

$ head -1 /usr/bin/tsc-20
#!/usr/bin/node-20

$ head -1 /usr/bin/tsc-22
#!/usr/bin/node-22
```