TypeScript 路徑設定與 tsconfig.json 路徑相關設定
前言
TypeScript 專案中,模組之間的匯入 (import) 路徑若處理不好,會變成地獄級相對路徑,例如:
1 | import { getUser } from "../../../utils/api"; |
為了解決這問題,我們需要理解 tsconfig.json 中與「路徑」有關的設定,特別是 baseUrl、paths、rootDir、outDir。
相對路徑與絕對路徑
相對路徑 (relative path)
- 開頭必須是
./或../ - 代表是以目前檔案的位置為起點
1 | // ./ 表示目前目錄 |
規則表
| 符號 | 意義 | 範例 | 實際對應 |
|---|---|---|---|
./ |
目前目錄 | ./utils/math |
從目前檔案的目錄去找 |
../ |
上一層 | ../config |
從目前檔案往上一層再往下找 |
../../ |
上兩層 | ../../types |
以此類推 |
若你寫 import x from "./";,代表要匯入目前目錄下的 index.ts 檔案。
絕對路徑 (absolute path)
- 不以
./或../開頭 - 依照
baseUrl設定來決定「從哪裡開始找」 - 可搭配
paths建立路徑別名 (alias) - 如果沒有設定
baseUrl,TypeScript 會將非相對路徑當作 npm 套件 去node_modules裡找
例:
1 | import { add } from "utils/math"; |
如果在 tsconfig.json 中設定 "baseUrl": "./src",那這行就代表:
「請從 src/ 目錄底下去找 utils/math.ts。」
rootDir 與 outDir
1 | { |
| 設定 | 功能 |
|---|---|
rootDir |
指定原始 TypeScript 檔案的來源資料夾,根據這個設定來決定 outDir 中的檔案相對路徑 |
outDir |
指定編譯後 JavaScript 檔案的輸出位置 |
範例結構:
1 | project/ |
編譯後:
1 | project/ |
baseUrl:設定模組搜尋的根
預設情況
TypeScript 會將非相對路徑當作 npm 套件 去 node_modules 裡找,因此:
1 | import { add } from "utils/math"; |
若沒設定 baseUrl,會報錯「找不到模組」。
正確設定方式
1 | { |
效果:
| 匯入語法 | 實際對應檔案 |
|---|---|
"utils/math" |
src/utils/math.ts |
"components/Button" |
src/components/Button.ts |
paths:建立路徑別名 (alias)
paths 可搭配 baseUrl 一起使用,讓路徑更語意化、更乾淨。
1 | { |
使用方式:
1 | import { Button } from "@components/Button"; |
對應:
1 | project/ |
在執行環境中啟用 alias
TypeScript 編譯器知道 alias,但執行環境 (Node.js、Vite、Webpack) 不一定知道。
Vite
1 | // vite.config.ts |
vite-tsconfig-paths 會自動讀取你的 tsconfig.json 裡的 "baseUrl" 和 "paths" 設定。
Webpack (需手動設定 resolve.alias)
Webpack 不會自動讀取 tsconfig,所以要在 webpack.config.js (或 .ts) 裡自己指定 alias。
1 | // webpack.config.js |
__dirname 表示當前檔案所在的資料夾:/Users/.../project。
path.resolve(__dirname, "src") 表示:/Users/.../project/src。
這樣你就能在專案中這樣寫:
1 | import { Button } from "@components/Button"; |
Webpack 的 alias 是「執行時期」設定。TypeScript 的 paths 是「編譯時期」設定。它們要同步一致,否則編譯能過、執行會失敗。
Node.js (執行原生 TypeScript 或編譯後 JS)
Node.js 本身不會讀 tsconfig.json,視執行方式不同,使用不同方法。最常使用 tsconfig-paths 套件:
1 | npm i tsconfig-paths -D |
在 package.json 修改啟動命令:
1 | { |
這樣 Node.js 在執行時會自動解析 tsconfig.json 裡的 alias。
include 與 exclude
控制 TypeScript 要編譯哪些檔案。
1 | { |
include:指定要包含的檔案或資料夾 (預設["**/*"])exclude:指定要忽略的檔案或資料夾 (預設["node_modules"])
tsconfig.json 完整範例
1 | { |
使用方式:
1 | import { Button } from "@components/Button"; |
總結
| 設定項目 | 功能 | 範例 |
|---|---|---|
rootDir |
原始 TypeScript 檔案的根目錄,決定「結構」 | "src" |
outDir |
編譯後 JS 輸出目錄 | "dist" |
baseUrl |
import 非相對路徑 module 的搜尋 (解析) 起點 |
"./src" |
paths |
自訂 alias | "@/*": ["*"] |
include |
指定要編譯的檔案,決定「範圍」 | "src/**/*" |
exclude |
排除不需編譯的檔案,決定「範圍」 | "node_modules" |
./→ 目前目錄../→ 上一層目錄- 沒有
./或../→ TypeScript 視為「非相對路徑」,依baseUrl尋找,或當作 npm 套件 去node_modules裡找 - 搭配
paths可建立語意化的 alias
參考資料:
TypeScript 官方文件:Module Resolution
Vite 官方文件:vite-tsconfig-paths 外掛