本文 AI 產出,尚未審核

TypeScript 編譯與設定:include / exclude 完全攻略


簡介

在使用 TypeScript 時,最常見的問題之一就是 編譯範圍 設定不當,導致不必要的檔案被編譯、或是重要的程式碼被忽略。tsconfig.json 中的 includeexclude 欄位正是用來控制 哪些檔案會被 TypeScript 編譯器 (tsc) 處理的核心機制。

掌握這兩個屬性的使用方法,不只可以縮短編譯時間、減少產生的錯誤訊息,還能讓專案結構更清晰、維護成本下降。本文將從概念說明、實作範例、常見陷阱與最佳實踐,一步步帶你建立正確的編譯設定。


核心概念

1. include 的基本原理

  • include 接受一個 字串陣列,每個字串都是 Glob pattern(類似 UNIX 的檔案匹配規則)。
  • 若未指定 include,預設會 包含 tsconfig.json 所在目錄下的 所有 .ts.tsx.d.ts 檔案(不含 node_modules)。
  • include 定義 要加入 的檔案,之後還會受到 exclude 的過濾。

範例 1:只編譯 src 目錄下的程式碼

{
  "compilerOptions": { "outDir": "dist" },
  "include": ["src/**/*.ts"]
}

這裡的 src/**/*.ts 表示「src 資料夾內,任意子目錄的所有 .ts 檔」。

2. exclude 的基本原理

  • exclude 同樣接受 Glob pattern 陣列,用來 排除 不想編譯的檔案或目錄。
  • 預設的排除項目已包含 node_modulesbower_componentsjspm_packages
  • exclude 的篩選會在 include 之後執行,也就是說先加入再排除

範例 2:排除測試檔與產出目錄

{
  "compilerOptions": { "outDir": "dist" },
  "include": ["src/**/*.ts"],
  "exclude": ["src/**/*.spec.ts", "dist"]
}

src/**/*.spec.ts 為測試檔,dist 為編譯後的輸出目錄,兩者都不需要再次被編譯。

3. filesinclude / exclude 的差異

  • files顯式列出 必須編譯的檔案,不會exclude 影響。
  • 若同時使用 filesinclude,最終編譯的檔案集合是 兩者的聯集(union),再經過 exclude 篩選。
  • 建議 盡量避免 同時使用 filesinclude,以免產生混淆。

範例 3:混用 filesinclude(不推薦)

{
  "compilerOptions": { "outDir": "dist" },
  "files": ["src/main.ts"],
  "include": ["src/**/*.ts"],
  "exclude": ["src/legacy/**/*.ts"]
}

這樣會先把 src/main.tssrc/**/*.ts 合併,再排除 src/legacy/**/*.ts。若 main.ts 位於 legacy 目錄,仍會被編譯,造成意外。

4. 進階 Glob 語法

Pattern 代表意義
* 匹配除 / 之外的任意字元(單層)
** 匹配任意深度的子目錄
? 匹配單一字元
[ab] 匹配方括號內的任意字元
! exclude 中可用於「排除」特定模式(例如 !src/**/test.ts

範例 4:同時包含 .ts.tsx,但排除 node_modules 內的檔案

{
  "compilerOptions": { "jsx": "react" },
  "include": ["src/**/*.{ts,tsx}"],
  "exclude": ["node_modules"]
}

5. extends 與基礎設定的結合

在大型專案中,常會把共用的編譯設定抽成 base tsconfig,再由子專案 extends。此時 include / exclude覆寫(override)基礎設定,而不是合併。

範例 5:子專案覆寫 exclude

// tsconfig.base.json
{
  "compilerOptions": { "target": "es2020", "module": "commonjs" },
  "exclude": ["node_modules"]
}

// tsconfig.json (子專案)
{
  "extends": "./tsconfig.base.json",
  "include": ["src/**/*.ts"],
  "exclude": ["src/**/*.test.ts"]   // 只排除測試檔,保留基礎的 node_modules 排除
}

常見陷阱與最佳實踐

陷阱 說明 解決方式
忘記排除 distbuild 編譯輸出目錄若未排除,會形成 無限遞迴(編譯器會把已編譯的 .js 再當作輸入) exclude 中加入 ["dist", "build"]
使用過度寬鬆的 include include: ["**/*"] 會把根目錄下的所有檔案都帶入編譯,浪費時間 限定在實際的程式碼根目錄,如 src/**/*.ts
同時使用 filesinclude 兩者的結合容易產生「不小心編譯了」的檔案 盡量只使用一種,若需要精確控制,直接使用 files
忽略預設的 node_modules 排除 手動指定 include 後,預設排除會失效,可能導致第三方套件被編譯 明確在 exclude 加入 node_modules,或使用 skipLibCheck
Glob 語法錯誤 src/*/*.ts 只匹配兩層子目錄,深層檔案會被遺漏 使用 ** 代表任意深度,或測試 pattern 是否正確

最佳實踐

  1. 先寫 include 再寫 exclude:先確定要編譯的範圍,再排除例外。
  2. 保持 exclude 包含輸出目錄:避免編譯產出再次被編譯。
  3. 使用 extends 共享設定:大型 monorepo 可把共用 exclude 放在 base config。
  4. 利用 exclude! 反向模式(TS 4.5 以上)精細控制。
  5. 在 CI 中驗證 tsconfig.json:加入一步 tsc --noEmit,確保設定不會意外漏編檔案。

實際應用場景

場景一:前端 React 專案 + Jest 測試

{
  "compilerOptions": {
    "target": "es2022",
    "module": "esnext",
    "jsx": "react-jsx",
    "outDir": "dist"
  },
  "include": ["src/**/*.tsx", "src/**/*.ts"],
  "exclude": [
    "node_modules",
    "dist",
    "**/*.spec.ts",
    "**/*.spec.tsx"
  ]
}
  • 目的:只編譯實際的 React 元件與業務程式碼,測試檔 (*.spec.*) 與產出目錄均排除。

場景二:Node.js 微服務 + Shared Library

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2019",
    "outDir": "build",
    "rootDir": "src"
  },
  "include": ["src/**/*.ts", "libs/**/*.ts"],
  "exclude": ["src/**/*.test.ts", "build"]
}
  • 目的src 為服務程式碼,libs 為共用函式庫,兩者皆編譯;測試檔與編譯產出排除。

場景三:Monorepo 多套件,使用基礎設定

// packages/core/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "include": ["src/**/*.ts"],
  "exclude": ["src/**/*.test.ts"]
}
  • 目的:所有子套件共用 tsconfig.base.jsoncompilerOptionsexclude(如 node_modules),僅在子套件自行加入測試檔排除。

總結

  • includeexclude控制 TypeScript 編譯範圍 的關鍵,合理配置可大幅提升編譯效率與專案可讀性。
  • 明確指定要編譯的目錄或檔案include),再 排除不需要的例外exclude),避免不必要的檔案被拉入編譯流程。
  • 注意 預設排除node_modules)會在自行設定 include 後失效,必須手動補回。
  • 在大型或多套件專案中,善用 extends 共享基礎設定,讓每個子專案只關心自己的 include / exclude
  • 最後,持續在 CI 中驗證 tsconfig.json,確保設定不會因新增檔案而產生意外的編譯行為。

掌握了 include / exclude 的使用技巧,你就能在任何規模的 TypeScript 專案中,建立乾淨、快速、可預測的編譯流程。祝開發順利!