模組:TypeScript#

穩定性:1.2 - 候選釋出

啟用#

在 Node.js 中有兩種方法可以啟用對 TypeScript 的執行時支援。

  1. 完全支援所有 TypeScript 的語法和功能,包括使用任意版本的 TypeScript,請使用第三方包。

  2. 若需輕量級支援,您可以使用內建的型別剝離功能。

完整的 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 語法替換為空格,並且不執行型別檢查。要啟用對不可擦除 TypeScript 語法的轉換(這需要生成 JavaScript 程式碼,例如 enum 宣告、引數屬性),請使用標誌 --experimental-transform-types。要停用此功能,請使用標誌 --no-experimental-strip-types

Node.js 會忽略 tsconfig.json 檔案,因此,依賴於 tsconfig.json 中設定的功能(例如路徑或將較新的 JavaScript 語法轉換為舊標準)被有意地不支援。要獲得完整的 TypeScript 支援,請參見完整的 TypeScript 支援

型別剝離功能被設計為輕量級的。透過有意不支援需要生成 JavaScript 程式碼的語法,並將內聯型別替換為空格,Node.js 可以在不需要源對映(source maps)的情況下執行 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 語法,請在最近的父級 package.json 檔案中新增 "type": "module"
  • .mts 檔案將始終作為 ES 模組執行,類似於 .mjs 檔案。
  • .cts 檔案將始終作為 CommonJS 模組執行,類似於 .cjs 檔案。
  • 不支援 .tsx 檔案。

與 JavaScript 檔案一樣,在 import 語句和 import() 表示式中,副檔名是強制性的import './file.ts',而不是 import './file'。出於向後相容性的原因,副檔名在 require() 呼叫中也是強制性的:require('./file.ts'),而不是 require('./file'),這類似於在 CommonJS 檔案中 require 呼叫強制要求使用 .cjs 副檔名。

tsconfig.jsonallowImportingTsExtensions 選項將允許 TypeScript 編譯器 tsc 對包含 .ts 副檔名的 import 說明符的檔案進行型別檢查。

TypeScript 功能#

由於 Node.js 僅移除內聯型別,任何涉及將 TypeScript 語法*替換*為新的 JavaScript 語法的 TypeScript 功能都會報錯,除非傳遞了 --experimental-transform-types 標誌。

需要轉換的最突出的功能是:

  • 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
} 

由於裝飾器(Decorators)目前是 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" 不會被轉換,因此會產生錯誤。最接近的可用功能是子路徑匯入,但其限制是必須以 # 開頭。