模块: TypeScript#

稳定性: 1.2 - 发布候选

启用#

有两种方法可以在 Node.js 中启用运行时 TypeScript 支持

  1. 完全支持所有 TypeScript 的语法和功能,包括使用任何版本的 TypeScript,请使用第三方包。

  2. 要获得轻量级支持,可以使用对类型剥离的内置支持。

完整的 TypeScript 支持#

要使用 TypeScript 并完全支持所有 TypeScript 功能(包括 tsconfig.json),可以使用第三方包。 这些说明使用 tsx 作为示例,但还有许多其他类似的库可用。

  1. 使用您为项目使用的任何包管理器,将该包作为开发依赖项安装。 例如,使用 npm

    npm install --save-dev tsx 
  2. 然后,您可以通过以下方式运行您的 TypeScript 代码

    npx tsx your-file.ts 

    或者,您可以通过以下方式使用 node 运行

    node --import=tsx your-file.ts 

类型剥离#

默认情况下,Node.js 将执行仅包含可擦除 TypeScript 语法的 TypeScript 文件。 Node.js 将用空格替换 TypeScript 语法,并且不执行类型检查。 要启用需要 JavaScript 代码生成(例如 enum 声明、参数属性)的不可擦除 TypeScript 语法的转换,请使用标志 --experimental-transform-types。 要禁用此功能,请使用标志 --no-experimental-strip-types

Node.js 忽略 tsconfig.json 文件,因此依赖于 tsconfig.json 中的设置(例如路径或将较新的 JavaScript 语法转换为较旧的标准)的功能是不受支持的。 要获得完整的 TypeScript 支持,请参阅完整的 TypeScript 支持

类型剥离功能旨在实现轻量级。 通过故意不支持需要 JavaScript 代码生成的语法,并通过用空格替换内联类型,Node.js 可以在不需要源映射的情况下运行 TypeScript 代码。

类型剥离与大多数版本的 TypeScript 兼容,但我们建议使用 5.8 或更高版本以及以下 tsconfig.json 设置

{
  "compilerOptions": {
     "noEmit": true, // Optional - see note below
     "target": "esnext",
     "module": "nodenext",
     "rewriteRelativeImportExtensions": true,
     "erasableSyntaxOnly": true,
     "verbatimModuleSyntax": true
  }
} 

如果您只打算执行 *.ts 文件(例如构建脚本),请使用 noEmit 选项。 如果您打算分发 *.js 文件,则不需要此标志。

确定模块系统#

Node.js 支持 TypeScript 文件中的 CommonJSES 模块语法。 Node.js 不会将一个模块系统转换为另一个模块系统; 如果您希望您的代码作为 ES 模块运行,您必须使用 importexport 语法,如果您希望您的代码作为 CommonJS 运行,您必须使用 requiremodule.exports

  • .ts 文件的模块系统将.js 文件相同的方式确定。 要使用 importexport 语法,请将 "type": "module" 添加到最近的父 package.json
  • .mts 文件将始终作为 ES 模块运行,类似于 .mjs 文件。
  • .cts 文件将始终作为 CommonJS 模块运行,类似于 .cjs 文件。
  • 不支持 .tsx 文件。

与 JavaScript 文件一样,文件扩展名在 import 语句和 import() 表达式中是强制性的import './file.ts',而不是 import './file'。 由于向后兼容性,文件扩展名在 require() 调用中也是强制性的:require('./file.ts'),而不是 require('./file'),类似于 .cjs 扩展名在 CommonJS 文件中的 require 调用中是强制性的。

tsconfig.json 选项 allowImportingTsExtensions 将允许 TypeScript 编译器 tsc 使用包含 .ts 扩展名的 import 说明符来类型检查文件。

TypeScript 功能#

由于 Node.js 仅删除内联类型,因此除非传递标志 --experimental-transform-types,否则任何涉及替换 TypeScript 语法为新的 JavaScript 语法的 TypeScript 功能都会出错。

需要转换的最突出的功能是

  • Enum 声明
  • 带有运行时代码的 namespace
  • 带有运行时代码的旧版 module
  • 参数属性
  • 导入别名

支持不包含运行时代码的 namespacesmodule。 此示例将正常工作

// This namespace is exporting a type
namespace TypeOnly {
   export type A = string;
} 

这将导致 ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX 错误

// This namespace is exporting a value
namespace A {
   export let x = 1
} 

由于装饰器目前是 TC39 Stage 3 提案,并且很快将被 JavaScript 引擎支持,因此它们不会被转换,并且会导致解析器错误。 这是一个临时限制,将来会得到解决。

此外,Node.js 不读取 tsconfig.json 文件,并且不支持依赖于 tsconfig.json 中的设置(例如路径或将较新的 JavaScript 语法转换为较旧的标准)的功能。

导入不带 type 关键字的类型#

由于类型剥离的性质,type 关键字是正确剥离类型导入所必需的。 如果没有 type 关键字,Node.js 将把导入视为值导入,这将导致运行时错误。 tsconfig 选项 verbatimModuleSyntax 可用于匹配此行为。

此示例将正常工作

import type { Type1, Type2 } from './module.ts';
import { fn, type FnParams } from './fn.ts'; 

这将导致运行时错误

import { Type1, Type2 } from './module.ts';
import { fn, FnParams } from './fn.ts'; 

非文件形式的输入#

可以为 --eval 和 STDIN 启用类型剥离。 模块系统将由 --input-type 确定,就像 JavaScript 一样。

REPL、--checkinspect 不支持 TypeScript 语法。

Source maps#

由于内联类型被空格替换,因此源映射对于堆栈跟踪中正确的行号是不必要的; 并且 Node.js 不会生成它们。 启用 --experimental-transform-types 后,默认情况下会启用源映射。

依赖项中的类型剥离#

为了阻止包作者发布用 TypeScript 编写的包,默认情况下,Node.js 将拒绝处理 node_modules 路径下文件夹内的 TypeScript 文件。

路径别名#

tsconfig "paths" 将不会被转换,因此会产生错误。 可用的最接近的功能是子路径导入,但限制是它们需要以 # 开头。