會寫 TypeScript 但你真的會 TS 編譯配置嗎?
最近遇到了挺多涉及到前端“編譯”方面的工作,其中關于 TypeScript 的編譯會涉及到關于 tsconfig.json 文件的配置,由于配置項繁雜,遂逐一解析并驗證,減少大家的一些疑惑,并提升工作效率!
隨著 TypeScript 的流行,越來越多的項目通過使用 TypeScript 來實現編寫代碼時候的類型提示和約束,從開發過程中減少 BUG 出現的概率,以此提升程序的健壯性和團隊的研發效率。
為什么會單獨寫一篇文章來講述 tsconfig.json 文件的配置吶?原因是筆者在做 TS 項目的時候,由于對其中的配置項不熟悉,搞來搞去,搞好久,煩死了!所以決定好好梳理下。
越來越多的項目用上了 TypeScript,因此如何按需配置 tsconfig 也應該是前端工程師需要掌握的技能之一。
本文內容結構如下,朋友們按需食用:
一、前置知識
在熟悉掌握 tsconfig.json 文件配置前,先給首次接觸 TS 的同學預備一下“前置知識”。
1.1 TypeScript 是什么?
TypeScript 官網:https://www.typescriptlang.org
TypeScript 是一種基于 JavaScript 的強類型編程語言,它使得在前端項目開發過程中更加嚴謹且流暢,一定程度上保證了大型前端項目程序的健壯性。
- TypeScript 是由微軟開發的一款開源的編程語言;
- TypeScript 是 JavaScript 的超集,遵循最新的 ESM 規范,TypeScript 擴展了 JavaScript 的語法;
- TypeScript 更像后端 JAVA、C# 這樣的面向對象語言,可以讓 JS 開發大型企業級項目。
但是 TypeScript 并不可以直接運行,而是需要轉換成 JavaScript 代碼才可以在 Node.js 或瀏覽器環境下執行,因此我們需要通過“編譯器”將 TS 代碼轉換為 JS 代碼。
1.2 什么是 tsc ?
tsc 的全稱是 TypeScript Compiler,也就是將 TypeScript 轉碼為 JavaScript 代碼的編譯器。
tsc 的全局安裝方式:
- npm install typescript -g
當我們編譯一份 index.ts 文件時,會使用下面的命令:
- tsc ./index.ts
這樣就可以得到一份編譯成為 JavaScript 代碼的 ./index.js 文件。
tsc 實際就是將 TS 轉為 JS 的編譯(器)腳手架工具,如果是一個 TS 的前端工程項目,那么就可以通過項目中的 tsconfig.json 文件來自定義配置 TS 編譯相關規則。
項目中的 tsconfig.json 文件,我們一般會通過如下快捷命令生成:
- tsc --init
執行完后,會在項目根目錄生成一個簡單的初始化 tsconfig.json 配置描述文件,如果沒有特別的要求,該初始化配置就足以支持你愉快地使用 TS 開發啦!
更多相關 TS 編譯配置和使用說明可以通過 tsc -h 查看。
1.3 tsconfig.json 文件
tsconfig.json[1] 文件是用于描述將 TypeScript 轉為 JavaScript 代碼的配置文件。
IDE(代碼編輯器)將會根據 tsconfig.json 文件來對當前項目中支持不同程度的類型約束,同時也是對 TSC 編譯 TypeScript 代碼過程做一些預定義、約束入口和編譯輸出目錄等配置。
因此對于一個支持 TypeScript 編程語言的工程來說,tsconfig.json 文件就是編碼的基礎。
二、tsconfig.json 配置詳解
有了上面的前置知識作為基石,相信大家會對 tsconfig.json 文件的配置項也會更加容易理解。
- tsconfig 的詳細配置:https://www.typescriptlang.org/tsconfig
- tsconfig 的協議描述網址:http://json.schemastore.org/tsconfig
tsconfig 協議
筆者將從常見的配置項單獨解釋,然后在最后會將一些不常用的配置統一解釋,朋友們可以將這篇文章收藏一下,可當作一份 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 是聲明是否需要在保存時候自動觸發 tsc 編譯的字段,一般來說,我們的代碼編譯過程會通過 Rollup、Webpack 等打包構建工具,并且使用熱更新,因此無需配置該項,保持缺省即可。
- {
- "compileOnSave": false,
- }
2.5 extendsextends
字段用于指明繼承已有的 tsconfig 配置規則文件。
該字段可以說是非常有用了,因為我們的 tsconfig 配置其實各個項目之間大同小異,因此完全可以結合自己團隊的情況,抽離一個基礎且公共的 tsconfig 配置,并將其發包,然后作為 extends 字段的值來繼承配置。
tsconfig 推薦默認配置可以參考官方的包:@tsconfig/recommended[2]
@tsconfig/recommended 的配置如下:
- {
- "compilerOptions": {
- "target": "ES2015",
- "module": "commonjs",
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true
- },
- "$schema": "https://json.schemastore.org/tsconfig",
- "display": "Recommended"
- }
例如繼承一個發包后的 tsconfig 基礎配置,并通過顯示聲明編譯的目標代碼版本為 ES2016 來覆蓋覆蓋 @tsconfig/recommended 中對應配置項。
- {
- "extends": "@tsconfig/recommended/tsconfig.json",
- "compilerOptions": {
- "target": "ES2016"
- }
- }
作為一些實踐經驗,社區也提供了一些常見環境(例如:Nuxt、Vite、Node 等)最佳實踐后的基礎配置,推薦參閱:https://github.com/tsconfig/bases/[3]
2.6 compilerOptions
compilerOptions 是一個描述 TypeScript 編譯器功能的“大”字段,其值類型是“對象”,因此包含了很多用于描述編譯器功能的子字段,其子字段的功能如下:
(1). target
target 字段指明經過 TSC 編譯后的 ECMAScript 代碼語法版本,根據 ECMAScript 語法標準,默認值為 ES3。
TypeScript 是 JavaScript 的超集,是對 JavaScript 語法和類型上的擴展,因此我們可以使用 ES5、ES6,甚至是最新的 ESNext[4] 語法來編寫 TS。例如當我們使用 ES2021 語法來編碼 TS 文件,同時配置如下:
- {
- "compilerOptions": {
- "target": "ES5",
- }
- }
則會將對應使用了最新 ECMAScript 語法的 TS 文件編譯為符合 ES5 語法規范的 *.js 文件。
延伸一下知識點,思考一下 tsc 是如何將高版本(ECMAScript 規范)代碼向低版本代碼轉換的?這個轉換的結果靠譜嗎?與 Babel 有何差異?
一圖看 ECMAScript 各版本功能差異
另外對于個版本差異有想簡單了解的👬,可以閱讀《1.5萬字概括ES6全部特性[5]》
通過一個實驗,在 src/index.ts 文件中使用了 Map、Async/Await、Promise、擴展運算符,并在 tsconfig.jon -> target 設置為 ES5:
驗證 target 降級處理
然后發現在右側的 dist/index.js 文件中,依然存在 new Map() 、Promise 語法,因此可以得出結論:tsc 的代碼降級編譯并不能完全處理兼容性。
通過官方文檔了解到:
這里提到了 lib 字段,意思是 target 不同的值會有對應默認的 lib 字段值,當然也支持開發者顯示指明 lib 字段的值,那么接下來看看 lib 是干嘛的吧!
(2). lib
lib 字段是用于為了在我們的代碼中顯示的指明需要支持的 ECMAScript 語法或環境對應的類型聲明文件。
例如我們的代碼會使用到瀏覽器中的一些對象 window、document,這些全局對象 API 對于 TypeScript Complier 來說是不能識別的:
lib 未顯示引入 DOM 會提示類型錯誤
因而需要在 lib 字段中如下配置:
- {
- "compilerOptions": {
- "target": "ES5",
- "lib": ["ES5", "ES6", "DOM"],
- }
- }
來顯式引入在 DOM 即瀏覽器環境下的一些默認類型定義,即可在代碼中使用,window、document 等瀏覽器環境中的對象,TS 在運行時以及編譯時就不會報類型錯誤。
引入類型定義后無錯誤提示
綜合 target 和 lib 字段的實際功能表現,我們可以得出結論:
TSC 的編譯結果只有部分特性做了 pollyfill 處理,ES6[6] 的一些特性仍然被保留,想要支持完全的降級到 ES5 還是需要額外引入 pollyfill(也就是我們在項目的入口文件處 import 'core-js'),但建議是將 target 字段值設置為 ES6,提升 TSC 的速度。
因此,筆者對于使用 TSC 編譯的觀點是:
不應該將 TSC 作為編譯項目的工具,應該將 TSC 作為類型檢查工具,代碼編譯的工作盡量交給 Rollup、Webpack 或 Babel 等打包工具!
另外推薦閱讀《為什么說用 babel 編譯 typescript 是更好的選擇》
(3). module
module 字段指明 tsc 編譯后的代碼應該符合何種“模塊化方案”,可以指定的枚舉值有:none, commonjs, amd, system, umd, es2015, es2020, 或 ESNext,默認值為 none。
在如今的前端開發趨勢來講,主要是使用 ESM、CommonJS、UMD、IIFE 四種模塊化方案,未來會趨向于 ESM,當然我們會根據項目的應用場景來決定使用何種模塊化方案,例如:NodeJS 使用 CommonJS,瀏覽器里可以使用 ESM,不過現在的打包工具,會自動處理 CommonJS 和 ESM 的差異,并包裝成符合指定模塊化規范的代碼,
在 tsconfig.json 可以設置 allowSyntheticDefaultImports 字段為 true,來允許合成默認導入。
(4). esModuleInterop
簡單來說,就是支持合成默認導入。
在前端項目開發時,使用 ESM 編寫代碼引入了 CJS 的模塊,由于 CJS 模塊沒有默認導出內容,因此需要通過我們的工具去自動化合成 CJS 的默認導出,以支持在 ESM 下流暢開發。
參閱文章《esModuleInterop 到底做了什么?[7]》,講得非常詳細也非常好。
當 esModuleInterop 字段設置為 true 時候,上述提到的 allowSyntheticDefaultImports 字段也會自動設置為 true。
(5). moduleResolution
moduleResolution 聲明如何處理模塊,枚舉值:classic、node,會根據 module 字段決定默認值。
推薦手動設置為 node,更符合現在大家的編碼認識一些,而且大部分的構建打包工具都是基于 Node。
舉個,遇到 import {a} from 'a-lib'; 這樣的模塊引入代碼應該如何去(解析)查找到對應的模塊文件。
(6). baseUrl & paths
baseUrl:設置基本目錄以解析非絕對模塊名稱(定義一個根目錄,以此進行絕對文件路徑解析)
paths:用于設置模塊名或路徑映射列表,這樣就可以簡寫項目中自定義模塊的文件路徑。
舉一個 :
- {
- "compilerOptions": {
- // 注意:baseUrl 必選,與 paths 成對出現,以 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[8] 插件,以及 TTypescript[9] 來轉換路徑別名為相對路徑。
由于當前的 TypeScript 不支持 tsconfig.json 中的自定義轉換器,且無法使用 tsc 命令使用自定義轉換器編譯文件,所以引入了 TTypescript 作為包裝器
- // tsconfig.json
- {
- "compilerOptions": {
- "baseUrl": "./",
- // 配置路徑別名映射
- "paths": {
- "@/*": ["src/*"]
- },
- "plugins": [
- // 轉換輸出 js 文件中的路徑
- { "transform": "typescript-transform-paths" },
- // 轉換輸出 .d.ts 文件中的路徑
- { "transform": "typescript-transform-paths", "afterDeclarations": true }
- ]
- }
- }
plugins[10] 是用于擴展 TSC 編譯器功能的字段。
例如在 Rollup 打包環境下,可以如下配置:
- 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 文件,一般我們會設置為 ./src 或 ./(即 tsconfig.json 所在目錄)
outDir:輸出目錄,即 tsc 編譯后的文件輸出的文件夾路徑(基于 tsconfig.json 文件的相對路徑)
例如:"outDir": "./dist",及將 TSC 編譯輸出的 JS 文件,統一輸出的 ./dist 目錄下。
(8). jsx
如果是有 jsx 語法需要支持的項目,可以設置值 preserve、react 等
- {
- "compilerOptions": {
- "jsx": "preserve", // 一般 preserve 即可
- },
- }
(9). importHelpers
importHelpers 決定是否啟用從 tslib 庫引入語法降級輔助函數,以避免重復冗余的輔助函數聲明。
個人建議是設置為 true 來啟用。
(10).experimentalDecorators
experimentalDecorators 用于聲明是否啟實驗性用裝飾器模式。
TypeScript 和 ES6 中引入了 Class 的概念,同時在 Decorators[11] 提出了裝飾器模式,通過引入裝飾器模式,能極大簡化書寫代碼。
當前對于 Decorator 的支持性不太好,如果是一些涉及到使用了裝飾器的需要,就需要開啟這個屬性。
(11). noEmit
noEmit 設置是否輸出 js 文件,一般是設置為 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, // 生成相應的 '.d.ts' 文件
- "declarationDir": "./dist/types", // 生成的 '.d.ts' 文件保存文件夾
- "sourceMap": true, // 生成相應的 '.map' 文件
- "outFile": "./", // 將輸出文件合并為一個文件
- "outDir": "./dist", // 指定輸出目錄
- "rootDir": "./", // 用來控制輸出目錄結構 --outDir.
- "removeComments": true, // 刪除編譯后的所有的注釋
- "noEmit": true, // 不生成輸出文件
- "importHelpers": true, // 從 tslib 導入輔助工具函數
- "isolatedModules": true, // 將每個文件做為單獨的模塊 (與 'ts.transpileModule' 類似).
- /* 嚴格的類型檢查選項 */
- "strict": true, // 啟用所有嚴格類型檢查選項
- "noImplicitAny": true, // 在表達式和聲明上有隱含的 any類型時報錯
- "strictNullChecks": true, // 啟用嚴格的 null 檢查
- "noImplicitThis": true, // 當 this 表達式值為 any 類型的時候,生成一個錯誤
- "alwaysStrict": true, // 以嚴格模式檢查每個模塊,并在每個文件里加入 'use strict'
- /* 額外的檢查 */
- "noUnusedLocals": true, // 有未使用的變量時,拋出錯誤
- "noUnusedParameters": true, // 有未使用的參數時,拋出錯誤
- "noImplicitReturns": true, // 并不是所有函數里的代碼都有返回值時,拋出錯誤
- "noFallthroughCasesInSwitch": true, // 報告switch語句的fallthrough錯誤。(即,不允許switch的case語句貫穿)
- /* 模塊解析選項 */
- "moduleResolution": "node", // 選擇模塊解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
- "baseUrl": "./", // 用于解析非相對模塊名稱的基礎目錄
- "paths": {}, // 模塊名到基于 baseUrl 的路徑映射的列表
- "rootDirs": [], // 根文件夾列表,其組合內容表示項目運行時的結構內容
- "typeRoots": [], // 包含類型聲明的文件列表
- "types": [], // 需要包含的類型聲明文件名列表
- "allowSyntheticDefaultImports": true, // 允許從沒有設置默認導出的模塊中默認導入。
- "esModuleInterop": true, // 支持合成模塊的默認導入
- /* Source Map Options */
- "sourceRoot": "./", // 指定調試器應該找到 TypeScript 文件而不是源文件的位置
- "mapRoot": "./", // 指定調試器應該找到映射文件而不是生成文件的位置
- "inlineSourceMap": true, // 生成單個 soucemaps 文件,而不是將 sourcemaps 生成不同的文件
- "inlineSources": true, // 將代碼與 sourcemaps 生成到一個文件中,要求同時設置了 --inlineSourceMap 或 --sourceMap 屬性
- /* 其他選項 */
- "experimentalDecorators": true, // 啟用裝飾器
- "emitDecoratorMetadata": true // 為裝飾器提供元數據的支持
- },
- /* 指定編譯文件或排除指定編譯文件 */
- "include": ["src/**/*"],
- "exclude": ["node_modules", "**/*.spec.ts"],
- "files": ["index.ts", "test.ts"],
- // 從另一個配置文件里繼承配置
- "extends": "@tsconfig/recommended",
- // 讓 IDE 在保存文件的時候根據 tsconfig.json 重新生成文件
- "compileOnSave": true // 支持這個特性需要Visual Studio 2015, TypeScript 1.8.4 以上并且安裝 atom-typescript 插件
- }
四、打包工具中的 TypeScript
前文講到了為什么不推薦直接使用 TSC 作為項目的打包編譯工具,那么接下來就簡單看看在常見的幾款打包工具中針對 TypeScript 的編譯方案是如何設計的?
4.1 Rollup + TypeScript
在 Rollup 打包中,我們一般只需要添加 @rollup/plugin-typescript[12] 插件即可,該插件會默認讀取項目根目錄下的 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()]
- };
結合其源碼:
默認使用 TSC 作為 TS 的編譯器
因為 typescript 聲明了是 peerDependencies,因此會采用項目中安裝的 typescript 版本,即是使用我們項目中的 TS 編譯器。
通過閱讀 @rollup/plugin-typescript 源碼,可以看到該插件會默認使我們自己項目中的 tsconfig.json 文件作為 TSC 編譯的配置,但會做一些配置預設覆蓋:
會調用 ts.parseJsonConfigFileContent() 方法,將 FORCED_COMPILER_OPTIONS 值 merge 到用戶的自定義配置中。
FORCED_COMPILER_OPTIONS
通過英文解釋看到,因為需要 TSC 編譯獲得 JS 產物,所以會將 noEmit 設置為 false,也就是 TSC 編譯會輸出文件,但為什么我們在輸出目錄卻沒有看到對應的 TSC 產物吶?
TSC 編譯結果存儲到內存中
但是如果開啟了 declaration,則會將 TSC 解析得到的 *.d.ts 文件輸出到指定目錄。
4.2 Webpack + TypeScript
在 Webpack 中的 TypeScript[13] 官方文檔中,指明了需要安裝: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 實現對 TypeScript 語法的編譯支持,再看看對 ts-loader 的介紹:
ts-loader
換句話說,ts-loader 實際調用了 TSC 來編譯 TS 文件,TSC 的配置依賴于你項目中的 tsconfig.json 文件。
如果使用了 Babel,則可以使用 @babel/preset-typescript[14] 來處理,但 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 代碼轉為 JS 代碼(通過 parse TS 文件為 AST,并直接移除類型信息,然后打印目標代碼),不會去做 TS 類型檢查,所以 Babel 編譯 TS 文件相較于 TSC 的速度更快!
同時,因為 Babel 會根據不同的兼容環境,按需引入 pollyfill,比 TSC 直接引入 core-js 更優雅,因此使用了 Babel 打包的體積也會更小。
TS 類型檢查工作可以交給代碼編輯器承擔,當然同時可以新增 TS 檢查的命令:
- // package.json
- {
- "script": {
- "tsCheck": "tsc --noEmit",
- }
- }
可以把類型檢查放到特定的 npm scripts 生命周期之前,另外其實也可以將類型檢查放到 git commit 階段,用于做必要的 TS 類型檢查,保證項目的正確性。
4.4 ESbuild + TypeScript
通過 Vite 體會到了 ESbuild[15] 帶來的開發熱更新“極速”體驗,針對 TS 項目,ESbuild 和 Babel 是相同的編譯策略,即僅編譯,不校驗類型。
ESbuild 處理 TypeScript[16] 同樣可以帶來飛一般的感覺!
Vite 使用 esbuild 將 TypeScript 轉譯到 JavaScript,約是 tsc 速度的 20~30 倍,同時 HMR 更新反映到瀏覽器的時間小于 50ms。—— Vite Docs[17]
但在 ESbuild 中需要啟用 tsconfig 中的 isolatedModules 功能,然后在類型引入的時候需要替換,規則參考如下:
- // old
- import { UserType } from './types';
- // new
- import type { UserType } from './types';
因為 ESbuild 是單獨編譯每個文件,無法判斷引入的是 Type(類型) 還是 值,所以需要開發者顯示地聲明是“Type”。
同時還需要啟用 esModuleInterop 功能,用于支持 ESM 模塊合成默認導入,以兼容 CJS 和 ESM 規范。
另外 ESbuild 不支持:emitDecoratorMetadat、const enum 類型和 *.d.ts 文件
此外,關注到兼容性處理這方面,Bable 和 ESbuild 是類似的,因此會存在兼容性問題:
兼容性
對于裝飾器處理不支持,因為 TS 是 JS 的超集,ESnext 的規范提案某些還不是穩定的,因此如果有這方面訴求的項目,可以借助 TSC 做預編譯,例如使用 Rollup 的 typescript 插件 或 Webpack 的 ts-loader 方式。
五、總結
針對 TypeScript 項目的類型檢查和編譯流程算是完整過了一遍,相信已足以支撐大家在工作中自定義化配置 TS 前端項目!
另外,tsconfig.json 推薦配置策略如下:
- 借助 extends 字段,并結合項目應用場景,繼承官方推薦配置
- 針對項目特點,按需修改對應功能配置
- 建議啟用 importHelpers、esModuleInterop,取消 noEmit 輸出
- TS 項目的打包構建,推薦使用 Webpack、Rollup、Bable 等專業工具來保證正確性和構建優化
參考資料
[1]TSconfig.json 手冊: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
[2]@tsconfig/recommended: https://www.npmjs.com/package/@tsconfig/recommended
[3]TSconfig 最佳實踐配置: https://github.com/tsconfig/bases/
[4]ES.Next 語法提案: https://github.com/tc39/proposals
[5]1.5萬字概括ES6全部特性: https://watesegmentfault.com/a/1190000020678240
[6]ES6 語法新特性: http://es6-features.org/#Constants
[7]esModuleInterop 到底做了什么?: https://zhuanlan.zhihu.com/p/148081795
[8]typescript-transform-paths: https://www.npmjs.com/package/typescript-transform-paths
[9]TTypescript: https://www.npmjs.com/package/ttypescript
[10]compilerOptions.plugins: https://www.typescriptlang.org/tsconfig#plugins
[11]Decorators: https://github.com/tc39/proposal-decorators
[12]@rollup/plugin-typescript: https://github.com/rollup/plugins/tree/master/packages/typescript/#readme
[13]Webpack 中的 TypeScript: https://webpack.docschina.org/guides/typescript/
[14]@babel/preset-typescript: https://babeljs.io/docs/en/babel-preset-typescript
[15]ESbuild: https://esbuild.github.io/
[16]ESbuild 處理 TypeScript: https://esbuild.github.io/content-types/#typescript
[17]Vite Docs: https://cn.vitejs.dev/guide/features.html#typescript