一些你需要掌握的 Tsconfig.Json 常用配置項(xiàng)
大家好,我是前端西瓜哥。
tsconfig.json 是用來配置 TS 編譯選項(xiàng)的,通常位于項(xiàng)目的根目錄位置。
我們可以用 ts 提供的 tsc 命令行工具,執(zhí)行 tsc --init。
復(fù)制$ tsc --init
Created a new tsconfig.json with: TS
target: es2016
module: commonjs
strict: true
esModuleInterop: true
skipLibCheck: true
forceConsistentCasingInFileNames: true
You can learn more at https://aka.ms/tsconfig
然后我們就能得到一個(gè)默認(rèn)的 tsconfig.json 文件,且這是一種可以添加注釋的 json 文件。
里面有很多帶有注釋的選項(xiàng),目的是讓開發(fā)者能夠反注釋快速啟用一些配置。
但注釋的選項(xiàng)太多了,所以我將它們移除了,得到下面的默認(rèn)配置:
復(fù)制{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
頂層配置
首先我們看配置最上層級的配置字段。
- compilerOptions:編譯器相關(guān)的選項(xiàng)。比如配置編譯成 ES5,模塊化使用 commonjs 等。這里的編譯配置很多,后面我們會(huì)講解一些常用的配置;
- files:指定需要被編譯的文件列表。這里不能指定目錄,只能是文件,可以省略.ts 后綴。適合需要編譯的文件比較少的情況。默認(rèn)值為 false;
- include:指定需要編譯的文件列表或匹配模式。include 可以通過通配符指定目錄,如"src/**/*" 表示 src 下的所有文件。如果沒有指定 files 配置,默認(rèn)值為 ** ,即項(xiàng)目下所有文件;如果配置了 files,默認(rèn)值為 [] 空數(shù)組;
- exclude:在 include 圈定的范圍內(nèi),排除掉一些文件。我們經(jīng)常用它來排除編譯輸出目錄、測試文件目錄、一些生成文件的腳本等文件。默認(rèn)值為 "node_modules,bower_componen";
- extends:繼承另一個(gè) ts 配置文件。這在 monorepo 的代碼組織中非常有用,不同的 package 可以通過 extends 繼承通用的 ts 配置。用法示例:"extends": "./common-tsconfig.json"。
- reference:引用。項(xiàng)目中如果有多個(gè)相互獨(dú)立的模塊,可以使用這個(gè)屬性來做分離。這樣一個(gè)模塊改變后,就只重新編譯這個(gè)模塊,其他模塊不重新編譯。編譯時(shí)要改用tsc --build。這在非常大的項(xiàng)目中應(yīng)該能有不小收益。
需要注意的是,files、include、exclude 只是指定編譯的入口文件范圍,如果其中的文件 import 了范圍外的 ts 文件,范圍外的文件依舊會(huì)被編譯。
在 VSCode 下,范圍外的 ts 文件不會(huì)應(yīng)用項(xiàng)目下的 tsconfig.json 配置。
常用的編譯器配置(compilerOptions)
接下來我們就來看看 compilerOptions 下的常用配置屬性。
因?yàn)榕渲庙?xiàng)實(shí)在很多,我就挑一些比較基本的進(jìn)行講解。
target
指定編譯的目標(biāo)版本。
tsc 也可以像 babel 一樣,可以將高版本的 TS / JS 編譯為低版本。你看這個(gè) tsc 腳本多大。
target 用于指定 TS 最后編譯出來的 ES 版本,默認(rèn)值是 ES3。
對于一些高版本引入的新 API 并,tsc 不會(huì)注入 polyfill,你需要自己全量引入 core-js,這點(diǎn)還是 babel 提供的按需引入 core-js 要更好一些。
當(dāng)然其他的不能 polyfill 的實(shí)現(xiàn),tsc 還是會(huì)做處理的。比如箭頭函數(shù)轉(zhuǎn)換為普通函數(shù),async / await 轉(zhuǎn)換為一大坨的等價(jià)代碼。
說實(shí)在的,ES3 實(shí)在有夠古老的,很多 API 都不支持,個(gè)人覺得默認(rèn)為 ES5 比較好。
我想大概是歷史原因,因?yàn)?TS 發(fā)布那會(huì),ES6 還沒出來,只有 ES5 編譯成 ES3 這一種情況。現(xiàn)在雖然 ES5 已經(jīng)廣泛支持了,但為了兼容還是保持默認(rèn)的 ES3。
target 支持的值有:es3、es5、es6(也叫 es2015)、es2016 一直到 es2022、然后還有 esnext。沒有 es7 這種東西,你得用 es2016。另外,esnext 指的是當(dāng)前版本的 TS 編譯器支持的最高版本。
這些值是大小寫敏感的,可以是 es5、ES5,或大小寫混雜。
通常來說前端項(xiàng)目會(huì)使用 es5。后端項(xiàng)目就看 nodejs 的版本支持 ES 的程度,像 Nestjs 腳手架生成的項(xiàng)目,taget 指定為 es2017。
lib
TypeScript 默認(rèn)自帶通用的 JS 內(nèi)置 API 的類型聲明,比如 Math、RegExp 等。
但 JS 運(yùn)行的環(huán)境各種各樣,會(huì)有一些特有的全局對象,比如瀏覽器下的 document,新的 ES 版本引入的新的 API。
為此,我們可以用 lib 這個(gè)屬性來設(shè)置需要引入的全局類型聲明。
lib 有高層級的:ES5、ES2015、DOM 、ESNEXT、WebWorker、ScriptHost 等。或是低層級模塊的 DOM.Iterable、ES2015.Core、ES2017.TypedArrays、 ES2018.Intl 等。高層級通常是多個(gè)全局類型聲明的組合。
lib 的默認(rèn)值通過 target 來指定,比如你的 target 指定為 ES7,它就會(huì)引入 ES7 的全局類型(大概是 lib.es2016.full.d.ts)。
但如果你想用最新版本的 ES 語法,但希望它能編譯成兼容性良好的 ES5,你就要手動(dòng)設(shè)置 lib,像下面這樣:
復(fù)制"target": "ES5",
"lib": [
"DOM",
"DOM.Iterable",
"ESNext"
]
lib 可以引入的全局類型聲明文件都在這個(gè)目錄下:
https://github.com/microsoft/TypeScript/blob/main/lib。
strict
啟用嚴(yán)格模式,能夠更能保證類型檢測的正確。
將 strict 設(shè)置為 true,會(huì)開啟一系列的嚴(yán)格的類型檢驗(yàn)配置。
比如 strictNullChecks 配置的默認(rèn)值會(huì)變成 true。這樣一些對象類型就不能賦值為 undefined 或 null,就能一定程度阻止 obj.prop 可能導(dǎo)致的 Cannot read properties of undefined 的運(yùn)行時(shí)錯(cuò)誤。
還比如 strictBindCallApply 默認(rèn)值變成 true。此時(shí),對函數(shù)使用 bind、call、apply,參數(shù)類型必須和原函數(shù)類型相同。如果是 false,則可以是任何類型。
此外還有很多其他的和嚴(yán)格模式相關(guān)的配置也會(huì)開啟。
建議開啟 strict,能減少 bug,缺點(diǎn)是要多寫一些類型推斷和分支判斷的代碼。
baseUrl
baseUrl 用于設(shè)置基礎(chǔ) url,可以幫我們省掉一些多余的路徑前綴。
比如我們原來要寫長長的:
復(fù)制import { Login } from "./src/features/user/login";
但如果我們設(shè)置 baseUrl 為 ./src,我們使用絕對路徑時(shí)就能去掉重復(fù)的前綴,將路徑寫短一些:
復(fù)制import { Login } from "features/user/login";
相對路徑不需要 baseUrl,因?yàn)樗窍鄬τ诋?dāng)前文件路徑計(jì)算的。
./src 的 . 為 tsconfig.json 配置文件所在的目錄路徑。其實(shí)寫成 src 也可以,它和 ./src 是等價(jià)的。
如果你不設(shè)置 baseUrl,模塊文件 import 需要使用相對路徑,或絕對路徑(不是針對項(xiàng)目根目錄的絕對路徑,而是完整的路徑)。
如果你想使用相對項(xiàng)目根目錄的路徑,你需要將 baseUrl 設(shè)置為 . 。
paths
路徑重映射。
要使用 paths,首先要設(shè)置好 baseUrl,paths 的源路徑和新路徑會(huì)使用 baseUrl 作為相對路徑計(jì)算。
復(fù)制"baseUrl": "./src",
"paths": {
"@lib/*": ["./other/_lib/*", "./other/_lib2/*"]
},
上面的配置,是將 other/_lib 和 other/_lib2 路徑重映射為 @lib。
這里的 @ 并不是必須的,這樣寫只是表明這個(gè)路徑是一個(gè)重映射,或者叫別名,實(shí)際上文件系統(tǒng)上不存在對應(yīng)的真實(shí)目錄。
這樣,原來比較冗長的路徑:
復(fù)制import LibA from "other/_lib/lib_a";
就可以改為:
復(fù)制import LibA from "@lib/lib_a";
declaration
是否給每個(gè)編譯出來的 JS 生成對應(yīng)的 d.ts 類型聲明文件。
TS 編譯后變成的 JS 是不攜帶類型信息的。如果你想要保留信息,就需要一個(gè) d.ts 文件來描述對應(yīng)的 JS 文件。
我們用 NPM 安裝的第三方包,這些包下的 package.json 文件的 types 屬性,就指定了這個(gè)包的類型文件。如果沒有顯式提供 types 屬性,則使用默認(rèn)的 index.d.ts。
declarationDir
指定編譯生成的類型聲明文件輸出的目錄。不提供的話,默認(rèn)和生成的 js 文件放在一起。
復(fù)制"declarationDir": "./types"
outDir
編譯文件的輸出目錄,默認(rèn)為 .,即項(xiàng)目根目錄。如果不設(shè)置它,編譯后的文件就會(huì)和源文件混雜在一起。通常我們會(huì)將 outDir 設(shè)置為 "./dist"。
outFile
將所有 ts 文件合并編譯生成一個(gè) js 文件和它的類型聲明 d.ts 文件。
這個(gè)配置項(xiàng)很少用,因?yàn)樗荒苡迷诓恢С帜K化導(dǎo)入的系統(tǒng),即所有的 ts 文件都是全局的。
換句話說,module 配置項(xiàng)需要為 None、System 或 AMD。
復(fù)制"outFile": "./app.js"
module
編譯后的 JS 使用哪種模塊系統(tǒng)。
模塊系統(tǒng)常用的有兩種:ESModule 和 CommonJS。前者是 ES 的標(biāo)準(zhǔn)(使用了 import 關(guān)鍵字),后者則是 Nodejs 的使用的模塊系統(tǒng)(使用了 require)。此外還有 AMD、UMD 等。
支持的值有:none、commonjs、amd、umd、system、es6/es2015、es2020、es2022、esnext、node16、nodenext。
它們的具體不同可以看官方文檔的代碼示例:
https://www.typescriptlang.org/tsconfig#module。
如果 target 是 ES3 或 ES5,默認(rèn)值是 CommonJS(畢竟 ES6 后才有的 ESModule);否則為 ES6/ES2015。
allowJs
將 js 文件也作為編譯對象,可以被 ts 文件引入。布爾值,默認(rèn)為 false。
types
類型聲明的一種引入方式是 @types 包,比如 React 框架使用了 flow 作為類型系統(tǒng),為了支持 TypeScript,React 團(tuán)隊(duì)又寫一套 d.ts 類型文件,發(fā)布到 @types/react 包上。
然后我們下載這個(gè)類型包后,并使用類似 import React from 'react',TS 會(huì)從從 node_modules/@types 中找到 react 文件夾,如果找不到,就會(huì)向上一層目錄繼續(xù)找,知道找到位置。如果存在,這個(gè) React 對象就會(huì)被賦予聲明的類型。
@types 可以是模塊類型聲明(像 React 類型),也可以是全局類型聲明(如 nodejs 的 process 對象類型)。
types 配置 可指定只使用哪些全局類型聲明,而不是 node_modules/@types 下所有的類型聲明。如:
復(fù)制"lib": [
"node", // 即 node_modules/@types/node
"jest"
]
typeRoots
前面說到 ts 會(huì)遞歸查找 node_modules/@types 去尋找類型聲明文件。
但你也可以用 typeRoots 來 指定只尋找特定目錄下的類型聲明文件,如:
復(fù)制"typeRoots": ["./typings", "./vendor/types"]
結(jié)尾
tsconfig 的配置非常多,但我想基本上掌握上面這幾個(gè)配置的使用就差不多了。
更多的配置項(xiàng)可以看官方文檔,建議自己構(gòu)建一個(gè) TS 項(xiàng)目進(jìn)行測試。