跳至主要内容

[TS] TypeScript Config File (tsconfig)

此篇為各筆記之整理,非原創內容,資料來源可見下方連結與文後參考資料。

TSC

$ npx tsc -b . # build
$ npx tsc -b . --clean # 移除掉打包後產生的檔案


$ npx tsc --showConfig > ts-config.txt # 檢視實際上被 TypeScript 處理的檔案(最終吃到的設定檔)
$ npx tsc --project tsconfig.json --diagnostics > ts-diagnostics.txt
多個 tsconfig 時,建議使用 tsc -b 來做檢查

如果專案中有多個 tsconfig 檔案,用 references 把對應的 configuration 組在一起,例如(同時有 tsconfig.node.jsontsconfig.app.jsontemplate-react-ts/tsconfig.json @ GitHub),則使用 tsc -b 來執行才會對每一個 tsconfig 的檔案來做檢查,如果只是執行 tsctsc --project tsconfig.json,則可能不會檢查到所有檔案。

參考:

Configuration

設定檔

提示

建議可以參考 The TSConfig Cheat Sheet @ Total TypeScript 的設定

如果是用 VS Code 的話,滑鼠移上去 property 就會顯示每個設定的描述:

  • compilerOptions
    • baseUrl:設成 "baseUrl": "./src" 則可以使用 absolute path 來載入模組
  • include:如果使用 glob pattern 但沒有指定副檔名的話,預設只會使用有支援的副檔名(例如,.ts.tsx.d.ts,如果 allowJstrue 的話,則會一併啟用 .js.jsx),這些指定的檔案會從 tsconfig.json 所放置的位置作為相對目錄。
  • exclude:從已經被 include 中的檔案中加以排除掉。
  • extends
    • 被繼承檔案的設定會先被載入,接著被該檔案內的設定加已覆蓋
    • 所有在設定檔中的相對路徑,都會根據原設定檔的位置加以解析
    • file, includeexclude 的內容會覆蓋掉被繼承的檔案中所寫的
    • 唯一一個不會被繼承的屬性是 references
    • 帶有相對路徑的屬性不會被繼承,而是會根據原設定檔中的相對路徑被解析

Type Checking 相關

建議打開下述的 flag:

Project 相關

Module 相關

  • module:指程式打包後使用的 module system,例如 commonjsumdnode16es2022、...等。
提示

module 主要指的是打包後使用的 module system,主要指和 module 有關的語法;另一個欄位 target 指的則是「程式語法」本身打包後要支援到的環境版本,例如,如果環境不支援 arrow function,則打包後會編譯成一般的 function 語法。

Debug 相關

除了在執行 tsc 時加上 --showConfig 外(即,npx tsx --showConfig),也可以在 tsconfig.json 中使用下述設定來 debug

  • diagnostics:顯示診斷報告,可以用來看 performance,例如,執行的時間、檢查了多少檔案、消耗的記憶體
  • explainFiles:顯示 TypeScript 處理了那些檔案,以及之所以被 TypeScript 檢查的原因
  • extendedDiagnostics:相較於 diagnostics 更完整的報告
  • generateCpuProfile
  • listEmittedFiles:顯示有那些被 emit 出來的檔案
  • listFiles:顯示有哪些檔案會被 TypeScript 給 compile,可以用來確定檔案有沒有被 TS 處理到,如果希望進一步了解回什麼會被 TS 處理到的原因,則可以改用 explainFiles
  • traceResolution
// tsconfig.json

/* Visit https://aka.ms/tsconfig.json to read more about this file */
{
"compilerOptions": {
/* Basic Options */
"target": "ES2018", // compile 後要支援到的 ECMAScript 版本
"module": "commonjs", // compile 後程式碼會用 commonjs 來處理模組的匯出匯入
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": false, // 是否允許匯入 js 檔,會影響到 include 時解析的副檔名是否包含(.js 和 .jsx)
"declaration": true,

// 如果沒設定會套用預設值(TS 自動判斷)
// 有「機會」導致 src 的資料夾也一起被 build 到 dist 資料夾中
// 例如 TS 自動把 rootDir 判斷為 { "rootDir": "." }
"rootDir": "src",

// 預設 tsc 會直接把編譯好的 js 檔放在與 ts 檔相同的路徑,但這樣檔案會很散亂,因此全部放到 dist
"outDir": "dist",

/* Strict Type-Checking Options */
"strict": true,

/* Additional Checks */
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true, // 確保 switch case 都會有 break 或 return

/* Module Resolution Options */
"baseUrl": "./", // 匯入模組時,路徑可以使用從 baseUrl 開始,而不需要 ./../ 這種寫法
"paths": {
"@": ["src"] // 將 @ map 到 src
},
"esModuleInterop": false,

/* Source Map Options */
"sourceMap": true,

/* Advanced Options */
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true // 確保檔案的大小寫一致,避免某些作業系統對大小寫不敏感
},
"include": ["src/**/*.ts"], // compiler 要做用在哪些檔案上
"exclude": []
}

如何提升 TypeScript compile、type-check、和 emit 的效率

keywords: performance

檢視編譯效能

首先,要檢視效能可以使用 tsconfig.json 中的 diagnosticsextendedDiagnostics(完整的資訊)的設定,如此會顯示 TypeScript compile 時所消耗的時間。

tsc performance improve

了解 TypeScript 處理了那些檔案

接著先看 TypeScript 實際處理了那些檔案:

  1. 可以使用 --showConfig 來檢視設定
npx tsc --showConfig > tsconfig.txt
  1. 或者在 tsconfig.json 中使用 listFilesexplainFiles 的 option 來檢視實際被 TypeScript 處理到的檔案

這時候也許可以看到一些不需要但被 TypeScript 處理的檔案,例如 storybook_releasepublic 等等:

image-20220520090305433

使用 exclude 排除不需要的檔案

把這些檔案加到 tsconfig.json 中的 exclude 中:

// tsconfig.json
{
"exclude": ["node_modules", "public", "storybook_release", "coverage"]
}

使用 incremental flag

可以在 tsconfig.json 中使用 incremental 的 option(如果專案本身時屬於 composite,則預設就會是 true)。

incremental 的功能讓 TypeScript 可以將前一次 compile 的資訊紀錄在名為 .tsbuildinfo 的檔案中,這麼做可以讓 TypeScript 知道只有那些最少的檔案需要被 re-checked/re-emitted,大幅減少 type-check 所需的時間。另外,這個檔案刪掉也沒關係,因為它單純只是用來加快 compile 速度的。

Restart TS Server

做完這些設定後,如果 VSCode 有一點「怪怪的」,可以重新啟動 VSCode 的 TypeScript Server:

image-20220520104504514

FAQ

src 資料夾也被 build 進 dist 資料夾中

tsconfig.json 中,加上 "rootDir": "src"(原因見上方說明)。

JSX 的選項要用那個?

參考資料
{
"compilerOptions": {
// "preserve":如果你不是用 tsc 來 compile App
// "react-jsx":如果你是用 tsc 來 compile App,且 React 的版本是 17 以上
// "jsx":如果你是用 tsc 來 compile App,且 React 的版本是 16 以下
"jsx": "preserve" // "preserve", "react"
}
}

在撰寫 React 時,有可能會看到這個錯誤訊息:

React refers to a UMD global, but the current file is a module. Consider adding an import instead.

這個錯誤訊息很可能是和在 tsconfig 中的 jsx 設定有關,這個項目是用來定義 .tsx 的檔案要如何在 build 時轉換成 .js。然而在多數的 React 專案中,都不會使用 tsc 來將專案做打包,TypeScript 單純是用作型別檢查,而不用來打包專案。

之所以會有這個錯誤,是因為預設的值是 jsx: react,這時候因為在打包後的檔案中會使用 React.createElement,因此就會需要在每次使用到 JSX 時,import React,否則會出現錯誤(參考這裡)。

既然我們並不是使用 TypeScript 來做打包,我們就可以請 TypeScript 不要管如何處理 .tsx 的打包方式:

  • jsx: preserve :就表示如果使用 TS 打包時,保持 JSX 不變
  • jsx: react-jsx:如果你使用的是 React 17 以後的版本,因為在 React 17 之後,並不需要在每次使用 JSX 時都 import React,這時候可以使用 react-jsx 這個選項

簡單來說,在目前多數的 React 專案中,可以使用 preservereact-jsx 的選項,而不是預設的 react