本文 AI 產出,尚未審核

TypeScript 基礎概念(Basics)

主題:tsconfig.json 設定


簡介

在使用 TypeScript 開發專案時,tsconfig.json 是整個編譯流程的指揮中心。它不僅決定了哪些檔案會被編譯、編譯結果的輸出位置,還能透過各種選項讓編譯器在開發階段即時捕捉潛在的錯誤。沒有妥善設定的 tsconfig.json,往往會導致「跑不通」或「執行時才出錯」的情況,降低開發效率,甚至增加維護成本。

本篇文章針對 初學者到中階開發者,從最基本的結構說起,逐步說明常見的編譯選項、路徑別名、嚴格模式等實務設定,並提供完整範例、常見陷阱與最佳實踐,幫助你快速掌握 tsconfig.json 的使用技巧,讓 TypeScript 在專案中發揮最大效益。


核心概念

1. tsconfig.json 的基本結構

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules", "dist"]
}
欄位 說明
compilerOptions 編譯器的所有設定,幾乎所有可調整行為都在此定義。
include 指定要納入編譯的檔案或目錄,支援 glob 模式。
exclude 排除不需要編譯的檔案或目錄,預設會排除 node_modules
files 若只想編譯特定檔案,可直接列出檔名(會覆寫 include/exclude)。

小技巧:若 includeexcludefiles 都未設定,TypeScript 會自動搜尋專案根目錄下的所有 *.ts*.tsx 檔案。


2. 常用編譯選項

2.1 target & module

{
  "compilerOptions": {
    "target": "ES2019",   // 編譯成的 ECMAScript 版本
    "module": "esnext"    // 產出模組系統(commonjs、esnext、amd…)
  }
}
  • target:決定產出的 JavaScript 語法等級,若設定 ES5,則會把 async/await 轉譯為 Promise+generator。
  • module:在 Node.js 環境常用 commonjs,在前端建置(Webpack、Vite)則多選 esnext 讓打包工具自行處理。

2.2 strict 系列

{
  "compilerOptions": {
    "strict": true,               // 開啟全部嚴格檢查
    "noImplicitAny": true,        // 隱式 any 會報錯
    "strictNullChecks": true,     // null/undefined 必須顯式處理
    "noImplicitThis": true,       // this 的類型必須明確
    "alwaysStrict": true          // 輸出 "use strict"
  }
}
  • 開啟 strict 後,TypeScript 會在編譯階段即捕捉大多數常見錯誤,是提升程式品質的第一步。

2.3 esModuleInterop & allowSyntheticDefaultImports

{
  "compilerOptions": {
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}
  • 允許 import foo from "foo" 直接匯入 CommonJS 模組,避免 defaultmodule.exports 的衝突。

3. 路徑別名(Path Alias)與根目錄

在大型專案中,相對路徑 (../../../utils) 常讓人閱讀困難。透過 pathsbaseUrl 可以建立簡潔的別名。

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@models/*": ["models/*"],
      "@utils/*": ["utils/*"]
    }
  }
}

使用方式

// src/services/userService.ts
import { User } from "@models/User";
import { formatDate } from "@utils/date";

export function getUserInfo(id: number) {
  // ...
}

注意:若使用 Webpack、Vite 或 ts-node 等執行環境,別忘了同步設定對應的別名(webpack.config.jsvite.config.tsts-node-r tsconfig-paths/register 等)。


4. 輸出設定:outDirrootDirdeclaration

{
  "compilerOptions": {
    "outDir": "./dist",          // 編譯結果放置目錄
    "rootDir": "./src",          // 原始碼根目錄
    "declaration": true,        // 產生 .d.ts 型別宣告檔
    "sourceMap": true,          // 產生 .map 供除錯使用
    "removeComments": false     // 保留註解(可設定 true 移除)
  }
}
  • declaration:若要將 TypeScript 套件發佈至 npm,建議開啟,讓使用者在 JavaScript 中也能得到型別提示。
  • sourceMap:在瀏覽器或 Node.js 除錯時,能直接對照到原始的 .ts 檔案。

5. 進階選項:incrementalwatchskipLibCheck

選項 作用 建議情境
incremental 啟用增量編譯,產生 .tsbuildinfo 檔,減少重建時間。 大型專案、CI/CD 中頻繁編譯。
watch 讓編譯器持續監看檔案變化,等同 tsc -w 開發階段本機快速迭代。
skipLibCheck 跳過 .d.ts 檔的型別檢查,提升編譯速度。 第三方套件型別不穩定時使用。

程式碼範例

範例 1:最小化的 tsconfig.json(適合小型腳本)

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

只要設定 targetmoduleoutDir,即可快速把 src 目錄下的 TypeScript 轉成 Node 可執行的 JavaScript。

範例 2:完整的前端專案設定(React + Vite)

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "esnext",
    "jsx": "react-jsx",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "baseUrl": "./src",
    "paths": {
      "@components/*": ["components/*"],
      "@hooks/*": ["hooks/*"]
    },
    "outDir": "./dist",
    "declaration": false,
    "sourceMap": true
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

範例 3:打造可發佈的 npm 套件

{
  "compilerOptions": {
    "target": "ES2019",
    "module": "commonjs",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "outDir": "lib",
    "rootDir": "src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src"],
  "exclude": ["tests", "node_modules"]
}

declaration + declarationMap 讓使用者在 IDE 中同時得到 .d.ts 與對應的來源映射,提升套件可用性。

範例 4:使用增量編譯加速 CI

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "incremental": true,
    "tsBuildInfoFile": "./.tsbuildinfo",
    "outDir": "build",
    "strict": true
  },
  "include": ["src"]
}

在 CI 中加入 --build 參數(tsc -b),會自動利用 .tsbuildinfo 只編譯變更過的檔案,節省大量時間。

範例 5:結合 ts-node 與路徑別名的執行方式

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "ES2020",
    "baseUrl": "./src",
    "paths": {
      "@app/*": ["*"]
    }
  },
  "ts-node": {
    "require": ["tsconfig-paths/register"]
  }
}
# 直接執行
npx ts-node -r tsconfig-paths/register src/index.ts

常見陷阱與最佳實踐

陷阱 可能原因 解決方式 / 最佳實踐
編譯後找不到模組 paths 設定未同步至打包工具(Webpack/Vite) 在相應的設定檔中也加入別名,或使用 tsconfig-paths 套件。
noImplicitAny 錯誤過多 第三方套件缺少型別定義 使用 --skipLibCheck 暫時忽略,或自行安裝 @types/...
strictNullChecks 造成大量錯誤 現有程式碼未處理 null/undefined 逐步開啟 strict,先從 strictNullChecks 開始,搭配 ! 斷言或 ?. 可緩解。
outDirrootDir 設錯 產出檔案結構與原始碼不對應,導致路徑錯誤 確認 rootDir 指向原始碼根目錄,outDir 指向最終輸出位置,並檢查 include/exclude
incremental 失效 tsconfig.json 被多次覆寫或 tsBuildInfoFile 被刪除 在 CI 中保留 .tsbuildinfo,或使用 -b(build mode)管理多個 tsconfig。

最佳實踐小結

  1. 先開 strict:即使會產生警告,也能在開發早期捕捉問題。
  2. 統一別名baseUrl + paths + 打包工具同步設定,避免相對路徑過深。
  3. 產出 .d.ts:對外發佈套件或大型前端庫時,務必開啟 declaration
  4. 利用增量編譯:大型專案或 CI/CD 流程中加速編譯。
  5. 保持 include/exclude 清晰:避免不必要的檔案被編譯,減少編譯時間。

實際應用場景

場景 tsconfig.json 典型設定 為何這樣設定
Node.js 後端服務 target: ES2020module: commonjsoutDir: ./diststrict: trueesModuleInterop: true Node 目前支援 ES2020,使用 CommonJS 讓 require 正常,嚴格模式提升 API 安全性。
React 前端專案(Vite) target: ES2022module: esnextjsx: react-jsxbaseUrl: ./srcpaths 別名、skipLibCheck: true Vite 依賴 ES 模組,react-jsx 為新版 JSX 轉譯,別名減少 import 雜訊。
共用 UI 元件庫(npm 套件) declaration: trueoutDir: ./libsourceMap: truestrict: trueesModuleInterop: true 發佈給其他開發者時,需要 .d.ts、source map 方便除錯,嚴格模式保證元件 API 穩定。
微服務多專案 Monorepo 每個子專案都有獨立 tsconfig.json,根目錄使用 references 連結 透過 Project References(references)實現跨套件型別檢查與增量編譯,提升整體建置效率。
測試環境(Jest + ts-jest) module: commonjsesModuleInterop: trueallowSyntheticDefaultImports: trueisolatedModules: true Jest 仍使用 CommonJS,isolatedModules 防止全域型別衝突,allowSyntheticDefaultImportsimport foo from 'foo' 正常運作。

總結

tsconfig.json 雖然看起來只是一個 JSON 檔,卻是 TypeScript 專案的*靈魂。*

  • 透過 compilerOptions 我們可以決定編譯目標、模組系統、嚴格檢查與輸出方式。
  • 路徑別名增量編譯型別宣告檔 等進階功能,讓大型專案的維護與效能都能得到顯著提升。
  • 常見的陷阱多與 設定不一致(例如別名未同步)或 過於寬鬆的型別檢查 有關,遵守最佳實踐即可減少問題。

在日常開發中,建議先以 最小可行的 tsconfig.json 起步,隨著需求逐步加入 strictpathsincremental 等設定,最終形成符合團隊工作流程的完整配置。只要掌握上述概念與範例,你就能在任何規模的 TypeScript 專案中,快速、穩定地完成編譯與除錯,讓開發體驗更加順暢。祝你寫程式愉快!