最近遇到了挺多涉及到前端“編譯”方面的工作,其中關(guān)于 TypeScript 的編譯會涉及到關(guān)于
tsconfig.json文件的配置,由于配置項繁雜,遂逐一解析并驗證,減少大家的一些疑惑,并提升工作效率!

隨著 TypeScript 的流行,越來越多的項目通過使用 TypeScript 來實現(xiàn)編寫代碼時候的類型提示和約束,從開發(fā)過程中減少 BUG 出現(xiàn)的概率,以此提升程序的健壯性和團隊的研發(fā)效率。
為什么會單獨寫一篇文章來講述 tsconfig.json 文件的配置吶?原因是筆者在做 TS 項目的時候,由于對其中的配置項不熟悉,搞來搞去,搞好久,煩死了!所以決定好好梳理下。

越來越多的項目用上了 TypeScript,因此如何按需配置 tsconfig 也應(yīng)該是前端工程師需要掌握的技能之一。
本文內(nèi)容結(jié)構(gòu)如下,朋友們按需食用??:

一、前置知識 ??
在熟悉掌握 tsconfig.json 文件配置前,先給首次接觸 TS 的同學預備一下“前置知識”。
1.1 TypeScript 是什么?
TypeScript 官網(wǎng):https://www.typescriptlang.org

TypeScript 是一種基于 JavaScript 的強類型編程語言,它使得在前端項目開發(fā)過程中更加嚴謹且流暢,一定程度上保證了大型前端項目程序的健壯性。
- TypeScript 是由微軟開發(fā)的一款開源的編程語言;
- TypeScript 是 JavaScript 的超集,遵循最新的 ESM 規(guī)范,TypeScript 擴展了 JavaScript 的語法;
- TypeScript 更像后端 JAVA、C# 這樣的面向?qū)ο笳Z言,可以讓 JS 開發(fā)大型企業(yè)級項目。
但是 TypeScript 并不可以直接運行,而是需要轉(zhuǎn)換成 JavaScript 代碼才可以在 Node.js 或瀏覽器環(huán)境下執(zhí)行,因此我們需要通過“編譯器”將 TS 代碼轉(zhuǎn)換為 JS 代碼。
1.2 什么是 tsc ?
tsc 的全稱是 TypeScript Compiler,也就是將 TypeScript 轉(zhuǎn)碼為 JavaScript 代碼的編譯器。
tsc 的全局安裝方式:
npm install typescript -g
當我們編譯一份 index.ts 文件時,會使用下面的命令:
tsc ./index.ts
這樣就可以得到一份編譯成為 JavaScript 代碼的 ./index.js 文件。
tsc 實際就是將 TS 轉(zhuǎn)為 JS 的編譯(器)腳手架工具,如果是一個 TS 的前端工程項目,那么就可以通過項目中的 tsconfig.json 文件來自定義配置 TS 編譯相關(guān)規(guī)則。
項目中的 tsconfig.json 文件,我們一般會通過如下快捷命令生成:
tsc --init
執(zhí)行完后,會在項目根目錄生成一個簡單的初始化 tsconfig.json 配置描述文件,如果沒有特別的要求,該初始化配置就足以支持你愉快地使用 TS 開發(fā)啦!
更多相關(guān) TS 編譯配置和使用說明可以通過 tsc -h 查看。
1.3 tsconfig.json 文件
tsconfig.json 文件是用于描述將 TypeScript 轉(zhuǎn)為 JavaScript 代碼的配置文件。
IDE(代碼編輯器)將會根據(jù) tsconfig.json 文件來對當前項目中支持不同程度的類型約束,同時也是對 TSC 編譯 TypeScript 代碼過程做一些預定義、約束入口和編譯輸出目錄等配置。
因此對于一個支持 TypeScript 編程語言的工程來說,tsconfig.json 文件就是編碼的基礎(chǔ)。
二、tsconfig.json 配置詳解 ??
有了上面的前置知識作為基石,相信大家會對 tsconfig.json 文件的配置項也會更加容易理解。
- tsconfig 的詳細配置:https://www.typescriptlang.org/tsconfig
- tsconfig 的協(xié)議描述網(wǎng)址:http://json.schemastore.org/tsconfig

筆者將從常見的配置項單獨解釋,然后在最后會將一些不常用的配置統(tǒng)一解釋,朋友們可以將這篇文章收藏一下,可當作一份 tsconfig 配置的中文查詢對照表 ??。
2.1 files
files 字段用于指明需要 tsc 編譯的一個或多個 ts 文件,例如:
{
"files": ["index.ts", "global.d.ts"],
}
當指定的文件或文件夾不存在時,會提示 ? 錯誤!
2.2 include
include 字段用于指明需要被 tsc 編譯的文件或文件夾列表,例如:
{
"include": [
"src",
"global.d.ts"
],
}
2.3 exclude
exclude 字段用于排除不需要 tsc 編譯的文件或文件夾列表,例如:
{
"exclude": ["test.ts", "src/test.ts"],
}
注意: exclude 字段中的聲明只對 include 字段有排除效果,對 files 字段無影響,即與 include 字段中的值互斥。
如果 tsconfig.json 文件中 files 和 include 字段都不存在,則默認包含 tsconfig.json 文件所在目錄及子目錄的所有文件,且排除在 exclude 字段中聲明的文件或文件夾。
2.4 compileOnSave
compileOnSave 是聲明是否需要在保存時候自動觸發(fā) tsc 編譯的字段,一般來說,我們的代碼編譯過程會通過 Rollup、Webpack 等打包構(gòu)建工具,并且使用熱更新,因此無需配置該項,保持缺省即可。
{
"compileOnSave": false,
}
2.5 extends
extends 字段用于指明繼承已有的 tsconfig 配置規(guī)則文件。
該字段可以說是非常有用了,因為我們的 tsconfig 配置其實各個項目之間大同小異,因此完全可以結(jié)合自己團隊的情況,抽離一個基礎(chǔ)且公共的 tsconfig 配置,并將其發(fā)包,然后作為 extends 字段的值來繼承配置。
tsconfig 推薦默認配置可以參考官方的包:@tsconfig/recommended
@tsconfig/recommended 的配置如下:
{
"compilerOptions": {
"target": "ES2015",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Recommended"
}
例如繼承一個發(fā)包后的 tsconfig 基礎(chǔ)配置,并通過顯示聲明編譯的目標代碼版本為 ES2016 來覆蓋覆蓋 @tsconfig/recommended 中對應(yīng)配置項。
{
"extends": "@tsconfig/recommended/tsconfig.json",
"compilerOptions": {
"target": "ES2016"
}
}
作為一些實踐經(jīng)驗,社區(qū)也提供了一些常見環(huán)境(例如:Nuxt、Vite、Node 等)最佳實踐后的基礎(chǔ)配置,推薦參閱:https://github.com/tsconfig/bases/
2.6 compilerOptions
compilerOptions 是一個描述 TypeScript 編譯器功能的“大”字段,其值類型是“對象”,因此包含了很多用于描述編譯器功能的子字段,其子字段的功能如下:
(1). target
target 字段指明經(jīng)過 TSC 編譯后的 ECMAScript 代碼語法版本,根據(jù) ECMAScript 語法標準,默認值為 ES3。
TypeScript 是 JavaScript 的超集,是對 JavaScript 語法和類型上的擴展,因此我們可以使用 ES5、ES6,甚至是最新的 ESNext 語法來編寫 TS。例如當我們使用 ES2021 語法來編碼 TS 文件,同時配置如下:
{
"compilerOptions": {
"target": "ES5",
}
}
則會將對應(yīng)使用了最新 ECMAScript 語法的 TS 文件編譯為符合 ES5 語法規(guī)范的 *.js 文件。
延伸一下知識點,思考一下 tsc 是如何將高版本(ECMAScript 規(guī)范)代碼向低版本代碼轉(zhuǎn)換的?這個轉(zhuǎn)換的結(jié)果靠譜嗎?與 Babel 有何差異?

另外對于個版本差異有想簡單了解的??,可以閱讀《1.5萬字概括ES6全部特性》
通過一個實驗,在 src/index.ts 文件中使用了 Map、Async/Await、Promise、擴展運算符,并在 tsconfig.jon -> target 設(shè)置為 ES5:

然后發(fā)現(xiàn)在右側(cè)的 dist/index.js 文件中,依然存在 new Map() 、Promise 語法,因此可以得出結(jié)論:tsc 的代碼降級編譯并不能完全處理兼容性。
通過官方文檔了解到:

這里提到了 lib 字段,意思是 target 不同的值會有對應(yīng)默認的 lib 字段值,當然也支持開發(fā)者顯示指明 lib 字段的值,那么接下來看看 lib 是干嘛的吧!
(2). lib
lib 字段是用于為了在我們的代碼中顯示的指明需要支持的 ECMAScript 語法或環(huán)境對應(yīng)的類型聲明文件。
例如我們的代碼會使用到瀏覽器中的一些對象 window、document,這些全局對象 API 對于 TypeScript Complier 來說是不能識別的:

因而需要在 lib 字段中如下配置:
{
"compilerOptions": {
"target": "ES5",
"lib": ["ES5", "ES6", "DOM"],
}
}
來顯式引入在 DOM 即瀏覽器環(huán)境下的一些默認類型定義,即可在代碼中使用,window、document 等瀏覽器環(huán)境中的對象,TS 在運行時以及編譯時就不會報類型錯誤。

綜合 target 和 lib 字段的實際功能表現(xiàn),我們可以得出結(jié)論:
TSC 的編譯結(jié)果只有部分特性做了 pollyfill 處理,ES6 的一些特性仍然被保留,想要支持完全的降級到 ES5 還是需要額外引入 pollyfill(也就是我們在項目的入口文件處 import 'core-js'),但建議是將 target 字段值設(shè)置為 ES6,提升 TSC 的速度。
因此,筆者對于使用 TSC 編譯的觀點是:
不應(yīng)該將 TSC 作為編譯項目的工具,應(yīng)該將 TSC 作為類型檢查工具,代碼編譯的工作盡量交給 Rollup、Webpack 或 Babel 等打包工具!
另外推薦閱讀《為什么說用 babel 編譯 typescript 是更好的選擇》
(3). module
module 字段指明 tsc 編譯后的代碼應(yīng)該符合何種“模塊化方案”,可以指定的枚舉值有:none, commonjs, amd, system, umd, es2015, es2020, 或 ESNext,默認值為 none。
在如今的前端開發(fā)趨勢來講,主要是使用 ESM、CommonJS、UMD、IIFE 四種模塊化方案,未來會趨向于 ESM,當然我們會根據(jù)項目的應(yīng)用場景來決定使用何種模塊化方案,例如:NodeJS 使用 CommonJS,瀏覽器里可以使用 ESM,不過現(xiàn)在的打包工具,會自動處理 CommonJS 和 ESM 的差異,并包裝成符合指定模塊化規(guī)范的代碼,
在 tsconfig.json 可以設(shè)置 allowSyntheticDefaultImports 字段為 true,來允許合成默認導入。
(4). esModuleInterop
簡單來說,就是支持合成默認導入。
在前端項目開發(fā)時,使用 ESM 編寫代碼引入了 CJS 的模塊,由于 CJS 模塊沒有默認導出內(nèi)容,因此需要通過我們的工具去自動化合成 CJS 的默認導出,以支持在 ESM 下流暢開發(fā)。
參閱文章《esModuleInterop 到底做了什么?》,講得非常詳細也非常好。
當 esModuleInterop 字段設(shè)置為 true 時候,上述提到的 allowSyntheticDefaultImports 字段也會自動設(shè)置為 true。
(5). moduleResolution
moduleResolution 聲明如何處理模塊,枚舉值:classic、node,會根據(jù) module 字段決定默認值。
推薦手動設(shè)置為 node,更符合現(xiàn)在大家的編碼認識一些,而且大部分的構(gòu)建打包工具都是基于 Node。
舉個??,遇到 import {a} from 'a-lib'; 這樣的模塊引入代碼應(yīng)該如何去(解析)查找到對應(yīng)的模塊文件。
(6). baseUrl & paths
baseUrl:設(shè)置基本目錄以解析非絕對模塊名稱(定義一個根目錄,以此進行絕對文件路徑解析)
paths:用于設(shè)置模塊名或路徑映射列表,這樣就可以簡寫項目中自定義模塊的文件路徑。
舉一個 ??:
{
"compilerOptions": {
// 注意:baseUrl 必選,與 paths 成對出現(xiàn),以 tsconfig.json 文件所在目錄開始
"baseUrl": ".",
"paths": {
// 映射列表
"@/*": [
"src/*"
],
"moduleA": [
"src/libs/moduleA"
]
}
}
}
// 代碼里這么寫
import Toast from '@/components/Toast.ts' // 模塊實際位置: src/components/Toast.ts
import TestModule from 'moduleA/index.js' // 模塊實際位置: src/libs/moduleA/index.js
?? 注意: 如果需要自動生成(導出)類型定義文件,TSC 不會處理路徑別名,需要引入 typescript-transform-paths 插件,以及 TTypescript 來轉(zhuǎn)換路徑別名為相對路徑。
由于當前的 TypeScript 不支持 tsconfig.json 中的自定義轉(zhuǎn)換器,且無法使用 tsc 命令使用自定義轉(zhuǎn)換器編譯文件,所以引入了 TTypescript 作為包裝器
// tsconfig.json
{
"compilerOptions": {
"baseUrl": "./",
// 配置路徑別名映射
"paths": {
"@/*": ["src/*"]
},
"plugins": [
// 轉(zhuǎn)換輸出 js 文件中的路徑
{ "transform": "typescript-transform-paths" },
// 轉(zhuǎn)換輸出 .d.ts 文件中的路徑
{ "transform": "typescript-transform-paths", "afterDeclarations": true }
]
}
}
plugins 是用于擴展 TSC 編譯器功能的字段。
例如在 Rollup 打包環(huán)境下,可以如下配置:
import typescript from '@rollup/plugin-typescript';
import ttypescript from 'ttypescript';
export default [
{
input: './src/index.ts',
output: {
dir: 'dist',
format: 'cjs',
entryFileNames: 'index.js',
},
plugins: [
typescript({
typescript: ttypescript,
}),
],
},
];
如果是有自動導出類型定義文件的需求,才需要搞這一套插件~
(7). rootDir & outDir
rootDir:指定 TypeScript 識別讀取的根目錄,用于所有非聲明輸入文件的最長公共路徑
例如:
'"rootDir": "./src",則 src 目錄下的 TS 文件不能引用 src 目錄以外的 ts 文件,一般我們會設(shè)置為./src或./(即 tsconfig.json 所在目錄)
outDir:輸出目錄,即 tsc 編譯后的文件輸出的文件夾路徑(基于 tsconfig.json 文件的相對路徑)
例如:
"outDir": "./dist",及將 TSC 編譯輸出的 JS 文件,統(tǒng)一輸出的./dist目錄下。
(8). jsx
如果是有 jsx 語法需要支持的項目,可以設(shè)置值 preserve、react 等
{
"compilerOptions": {
"jsx": "preserve", // 一般 preserve 即可
},
}
(9). importHelpers
importHelpers 決定是否啟用從 tslib 庫引入語法降級輔助函數(shù),以避免重復冗余的輔助函數(shù)聲明。
個人建議是設(shè)置為 true 來啟用。
(10).experimentalDecorators
experimentalDecorators 用于聲明是否啟實驗性用裝飾器模式。
TypeScript 和 ES6 中引入了 Class 的概念,同時在 Decorators 提出了裝飾器模式,通過引入裝飾器模式,能極大簡化書寫代碼。
當前對于 Decorator 的支持性不太好,如果是一些涉及到使用了裝飾器的需要,就需要開啟這個屬性。
(11). noEmit
noEmit 設(shè)置是否輸出 js 文件,一般是設(shè)置為 false,將打包等工作交給 Webpack 等工具。
三、tsconfig.json 全解析 ??
上面針對 tsconfig.json 中一些常見配置做了詳細解釋,將一些不常用的配置字段組合在一起,做一個 Checklist 如下:
{
"compilerOptions": {
/* 基本選項 */
"target": "es6", // 指定 ECMAScript 目標版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
"module": "commonjs", // 指定使用模塊: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
"lib": [], // 指定要包含在編譯中的庫文件
"allowJs": true, // 允許編譯 javascript 文件
"checkJs": true, // 報告 javascript 文件中的錯誤
"jsx": "preserve", // 指定 jsx 代碼的生成: 'preserve', 'react-native', or 'react'
"declaration": true, // 生成相應(yīng)的 '.d.ts' 文件
"declarationDir": "./dist/types", // 生成的 '.d.ts' 文件保存文件夾
"sourceMap": true, // 生成相應(yīng)的 '.map' 文件
"outFile": "./", // 將輸出文件合并為一個文件
"outDir": "./dist", // 指定輸出目錄
"rootDir": "./", // 用來控制輸出目錄結(jié)構(gòu) --outDir.
"removeComments": true, // 刪除編譯后的所有的注釋
"noEmit": true, // 不生成輸出文件
"importHelpers": true, // 從 tslib 導入輔助工具函數(shù)
"isolatedModules": true, // 將每個文件做為單獨的模塊 (與 'ts.transpileModule' 類似).
/* 嚴格的類型檢查選項 */
"strict": true, // 啟用所有嚴格類型檢查選項
"noImplicitAny": true, // 在表達式和聲明上有隱含的 any類型時報錯
"strictNullChecks": true, // 啟用嚴格的 null 檢查
"noImplicitThis": true, // 當 this 表達式值為 any 類型的時候,生成一個錯誤
"alwaysStrict": true, // 以嚴格模式檢查每個模塊,并在每個文件里加入 'use strict'
/* 額外的檢查 */
"noUnusedLocals": true, // 有未使用的變量時,拋出錯誤
"noUnusedParameters": true, // 有未使用的參數(shù)時,拋出錯誤
"noImplicitReturns": true, // 并不是所有函數(shù)里的代碼都有返回值時,拋出錯誤
"noFallthroughCasesInSwitch": true, // 報告switch語句的fallthrough錯誤。(即,不允許switch的case語句貫穿)
/* 模塊解析選項 */
"moduleResolution": "node", // 選擇模塊解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
"baseUrl": "./", // 用于解析非相對模塊名稱的基礎(chǔ)目錄
"paths": {}, // 模塊名到基于 baseUrl 的路徑映射的列表
"rootDirs": [], // 根文件夾列表,其組合內(nèi)容表示項目運行時的結(jié)構(gòu)內(nèi)容
"typeRoots": [], // 包含類型聲明的文件列表
"types": [], // 需要包含的類型聲明文件名列表
"allowSyntheticDefaultImports": true, // 允許從沒有設(shè)置默認導出的模塊中默認導入。
"esModuleInterop": true, // 支持合成模塊的默認導入
/* Source Map Options */
"sourceRoot": "./", // 指定調(diào)試器應(yīng)該找到 TypeScript 文件而不是源文件的位置
"mapRoot": "./", // 指定調(diào)試器應(yīng)該找到映射文件而不是生成文件的位置
"inlineSourceMap": true, // 生成單個 soucemaps 文件,而不是將 sourcemaps 生成不同的文件
"inlineSources": true, // 將代碼與 sourcemaps 生成到一個文件中,要求同時設(shè)置了 --inlineSourceMap 或 --sourceMap 屬性
/* 其他選項 */
"experimentalDecorators": true, // 啟用裝飾器
"emitDecoratorMetadata": true // 為裝飾器提供元數(shù)據(jù)的支持
},
/* 指定編譯文件或排除指定編譯文件 */
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"],
"files": ["index.ts", "test.ts"],
// 從另一個配置文件里繼承配置
"extends": "@tsconfig/recommended",
// 讓 IDE 在保存文件的時候根據(jù) tsconfig.json 重新生成文件
"compileOnSave": true // 支持這個特性需要Visual Studio 2015, TypeScript 1.8.4 以上并且安裝 atom-typescript 插件
}
四、打包工具中的 TypeScript ??
前文講到了為什么不推薦直接使用 TSC 作為項目的打包編譯工具,那么接下來就簡單看看在常見的幾款打包工具中針對 TypeScript 的編譯方案是如何設(shè)計的?
4.1 Rollup + TypeScript
在 Rollup 打包中,我們一般只需要添加 @rollup/plugin-typescript 插件即可,該插件會默認讀取項目根目錄下的 tsconfig.json 配置文件。
Rollup 的配置就像這樣:
// file: rollup.config.js
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/index.ts',
output: {
dir: 'output',
format: 'cjs'
},
plugins: [typescript()]
};
結(jié)合其源碼:

因為 typescript 聲明了是 peerDependencies,因此會采用項目中安裝的 typescript 版本,即是使用我們項目中的 TS 編譯器。
通過閱讀 @rollup/plugin-typescript 源碼,可以看到該插件會默認使我們自己項目中的 tsconfig.json 文件作為 TSC 編譯的配置,但會做一些配置預設(shè)覆蓋:
會調(diào)用 ts.parseJsonConfigFileContent() 方法,將 FORCED_COMPILER_OPTIONS 值 merge 到用戶的自定義配置中。

通過英文解釋看到,因為需要 TSC 編譯獲得 JS 產(chǎn)物,所以會將 noEmit 設(shè)置為 false,也就是 TSC 編譯會輸出文件,但為什么我們在輸出目錄卻沒有看到對應(yīng)的 TSC 產(chǎn)物吶?

但是如果開啟了 declaration,則會將 TSC 解析得到的 *.d.ts 文件輸出到指定目錄。
4.2 Webpack + TypeScript
在 Webpack 中的 TypeScript 官方文檔中,指明了需要安裝:typescript 和 ts-loader 兩個模塊。
配置 Webpack 并支持 TypeScript 的配置如下:
// file: webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
可以看出 Webpack 主要是依賴 ts-loader 實現(xiàn)對 TypeScript 語法的編譯支持,再看看對 ts-loader 的介紹:

換句話說,ts-loader 實際調(diào)用了 TSC 來編譯 TS 文件,TSC 的配置依賴于你項目中的 tsconfig.json 文件。
如果使用了 Babel,則可以使用 @babel/preset-typescript 來處理,但 Babel 不會做 TS 類型校驗,在打包工具 Rollup 和 Webpack 中都可以引入 Babel,那么接下來看看 Babel 是如何處理 TypeScript 的吧!
4.3 Babel + TypeScript
Babel 處理 TS 需要安裝 @babel/preset-typescript 模塊,然后在 babel 項目配置文件中聲明:
// 配置說明:https://babeljs.io/docs/en/babel-preset-typescript
{
"presets": ["@babel/preset-typescript"]
}
但 Babel 中只會對 TS 代碼轉(zhuǎn)為 JS 代碼(通過 parse TS 文件為 AST,并直接移除類型信息,然后打印目標代碼),不會去做 TS 類型檢查,所以 Babel 編譯 TS 文件相較于 TSC 的速度更快!
同時,因為 Babel 會根據(jù)不同的兼容環(huán)境,按需引入 pollyfill,比 TSC 直接引入 core-js 更優(yōu)雅,因此使用了 Babel 打包的體積也會更小。
TS 類型檢查工作可以交給代碼編輯器承擔,當然同時可以新增 TS 檢查的命令:
// package.json
{
"script": {
"tsCheck": "tsc --noEmit",
}
}
可以把類型檢查放到特定的 npm scripts 生命周期之前,另外其實也可以將類型檢查放到 git commit 階段,用于做必要的 TS 類型檢查,保證項目的正確性。
4.4 ESbuild + TypeScript
通過 Vite 體會到了 ESbuild 帶來的開發(fā)熱更新“極速”體驗,針對 TS 項目,ESbuild 和 Babel 是相同的編譯策略,即僅編譯,不校驗類型。
ESbuild 處理 TypeScript 同樣可以帶來飛一般的感覺!
Vite 使用 esbuild 將 TypeScript 轉(zhuǎn)譯到 JavaScript,約是 tsc 速度的 20~30 倍,同時 HMR 更新反映到瀏覽器的時間小于 50ms?!?Vite Docs
但在 ESbuild 中需要啟用 tsconfig 中的 isolatedModules 功能,然后在類型引入的時候需要替換,規(guī)則參考如下:
// old
import { UserType } from './types';
// new
import type { UserType } from './types';
因為 ESbuild 是單獨編譯每個文件,無法判斷引入的是 Type(類型) 還是 值,所以需要開發(fā)者顯示地聲明是“Type”。
同時還需要啟用 esModuleInterop 功能,用于支持 ESM 模塊合成默認導入,以兼容 CJS 和 ESM 規(guī)范。
另外 ESbuild 不支持:emitDecoratorMetadat、const enum 類型和 *.d.ts 文件
此外,關(guān)注到兼容性處理這方面,Bable 和 ESbuild 是類似的,因此會存在兼容性問題:

對于裝飾器處理不支持,因為 TS 是 JS 的超集,ESnext 的規(guī)范提案某些還不是穩(wěn)定的,因此如果有這方面訴求的項目,可以借助 TSC 做預編譯,例如使用 Rollup 的 typescript 插件 或 Webpack 的 ts-loader 方式。
五、總結(jié) ??
針對 TypeScript 項目的類型檢查和編譯流程算是完整過了一遍,相信已足以支撐大家在工作中自定義化配置 TS 前端項目!
另外,tsconfig.json 推薦配置策略如下:
- 借助 extends 字段,并結(jié)合項目應(yīng)用場景,繼承官方推薦配置
- 針對項目特點,按需修改對應(yīng)功能配置
- 建議啟用
importHelpers、esModuleInterop,取消noEmit輸出 - TS 項目的打包構(gòu)建,推薦使用 Webpack、Rollup、Bable 等專業(yè)工具來保證正確性和構(gòu)建優(yōu)化

朋友們可以關(guān)注微信公眾號:DYBOY,來一起玩耍呀~