TypeScript 配置文件該怎么寫(xiě)?
前言
這篇文章是我的 TypeScript 系列的第 5 篇。今天我們就來(lái)看下, TypeScript 的配置文件 tsconfig.json 該如何寫(xiě)。
和 package.json 一樣, 它也是一個(gè) JSON 文件。package.json 是包描述文件,對(duì)應(yīng)的 Commonjs 規(guī)范,而 tsconfig.json 是最終被 TypeScript Compiler 解析和使用的一個(gè) JSON 文件。 TypeScript Compiler 用這個(gè)配置文件來(lái)決定如何對(duì)項(xiàng)目進(jìn)行編譯。
說(shuō)到編譯,不得不提一個(gè)知名選手 - babel。 和 TypeScript 類(lèi)似, 他們都可以將一種語(yǔ)法靜態(tài)編譯成另外一種語(yǔ)法。如果說(shuō)我想編譯一個(gè)文件,我只需要告訴 babel 我的文件路徑即可。
- npx babel script.js
有時(shí)候我想編譯整個(gè)文件夾:
- npx babel src --out-dir lib
babel 也可以指定輸出目錄,指定需要忽略的文件或目錄等等, TypeScript 也是一樣!你當(dāng)然可以像 babel 一樣在命令行中全部指定好,也可以將這些配置放到 tsconfig.json 中,以配置文件的形式傳遞給 TypeScript Compiler 。 這就是 tsconfig.json 文件的初衷,即接受用戶輸入作為配置項(xiàng)。
初探 tsconfig
我們先來(lái)看一個(gè)簡(jiǎn)單的 tsconfig 文件。
- {
- "compilerOptions": {
- "outDir": "./built",
- "allowJs": true,
- "target": "es5"
- },
- "include": ["./src/**/*"]
- }
如上配置做了:
- 讀取所有可識(shí)別的 src 目錄下的文件(通過(guò) include)。
- 接受 JavaScript 做為輸入(通過(guò) allowJs)。
- 生成的所有文件放在 built 目錄下(通過(guò) outDir)。
- 將 JavaScript 代碼降級(jí)到低版本比如 ECMAScript 5(通過(guò) target)。
實(shí)際項(xiàng)目有比這個(gè)更復(fù)雜。 接下來(lái), 我們來(lái)進(jìn)一步解讀。 不過(guò)在講配置項(xiàng)之前,我們先來(lái)看下 tsconfig.json 是如何被解析的。
tsconfig 是如何被解析的?
如果一個(gè)目錄下存在一個(gè) tsconfig.json 文件,那么意味著這個(gè)目錄是 TypeScript 項(xiàng)目的根目錄。 如果你使用 tsc 編譯你的項(xiàng)目,并且沒(méi)有顯式地指定配置文件的路徑,那么 tsc 則會(huì)逐級(jí)向上搜索父目錄尋找 tsconfig.json ,這個(gè)過(guò)程類(lèi)似 node 的模塊查找機(jī)制。
如圖:
- 在 _uglify-js@3.7.2@uglify-js 下執(zhí)行 tsc 則會(huì)找到 配置文件 1,在 _uglify-js@3.7.2@uglify-js/bin 下執(zhí)行 tsc 也會(huì)找到 配置文件 1
- 同理在 lib,node_modules 也會(huì)找到 配置文件 1
- 在 _uglify-js@3.7.2@uglify-js/bin/lucifer 下執(zhí)行 tsc 則會(huì)找到 配置文件 2
- 在 _uglify-js@3.7.2@uglify-js/lib/lucifer 下執(zhí)行 tsc 則會(huì)找到 配置文件 3
我在 上帝視角看 TypeScript 一種講述了 TypeScript 究竟做了什么,帶你從宏觀的角度看了一下 TypeScript。 其中提到了 TypeScript 編譯器會(huì)接受文件或者文件集合作為輸入,最終轉(zhuǎn)換為 JavaScript(noEmit 為 false) 和 .d.ts(declarations 為 true)。
這里其實(shí)還少了一個(gè)點(diǎn),那就是除了接受文件或者文件集合作為輸入,還會(huì)接受 tsconfig.json。tsconfig.json 的內(nèi)容決定了編譯的范圍和行為,不同的 配置可能會(huì)得到不同的輸出,或者得到不同的檢查結(jié)果。
當(dāng) tsc 找到了一個(gè) tsconfig.json 文件,那么其規(guī)定的編譯目錄則全部會(huì)被 typescript 處理,當(dāng)然也包括其依賴的文件。 如果 tsc 沒(méi)有找到一個(gè) tsconfig.json 或 tsconfig 沒(méi)有有效信息,那么 tsc 會(huì)使用默認(rèn)配置。 比如 tsconfig 是一個(gè)空的就沒(méi)有有效信息:
- {}
tsconfig 的全部屬性,以及屬性的默認(rèn)值可以在這里找到: http://json.schemastore.org/t...
總結(jié)一下 tsc 解析 tsconfig.json 的邏輯。
- 如果命令行指定了配置選項(xiàng)或者指定了配置文件的路徑,那么直接會(huì)讀取。
- 根據(jù) tsconfig json schema 校驗(yàn)是否格式正確。
- 如果正確,則將其和默認(rèn)配置合并(如果有 extends 字段,也會(huì)一起合并),將合并后的配置傳遞給 TypeScript 編譯器并開(kāi)始編譯。
- 否則拋出錯(cuò)誤
- 根據(jù) tsconfig json schema 校驗(yàn)是否格式正確。
- 否則,會(huì)從當(dāng)前目錄查找 tsconfig.json 文件, 如果找不到則逐層向上搜索父目錄。
- 如果找到了則會(huì)去根據(jù) tsconfig json schema 校驗(yàn)是否格式正確。
- 如果正確,則將其和默認(rèn)配置合并(如果有 extends 字段,也會(huì)一起合并),將合并后的配置傳遞給 TypeScript 編譯器并開(kāi)始編譯。
- 否則拋出錯(cuò)誤
- 否則,始終找不到則直接使用默認(rèn)配置
- 如果找到了則會(huì)去根據(jù) tsconfig json schema 校驗(yàn)是否格式正確。
tsconfig 的頂層屬性
tsconfig 的頂層屬性(Top Level)不多,主要有:compilerOptions, files, include, exclude,extends,compileOnSave等。
- compilerOptions 是重頭戲,其屬性也是最多的,我們的項(xiàng)目也是對(duì)這個(gè)定制比較多,這個(gè)我后面會(huì)重點(diǎn)講。
- files 則是你需要編譯的文件
- exclude 則是你不需要編譯的文件目錄(支持 glob)
- include 是你需要編譯的文件目錄(支持 glob)
- extends 就是繼承另外一個(gè)配置文件,TypeScript 會(huì)對(duì)其進(jìn)行合并,多項(xiàng)目公共配置有用。你也可以直接繼承社區(qū)的“最佳實(shí)踐”,比如:
- {
- "extends": "@tsconfig/node12/tsconfig.json",
- "compilerOptions": {},
- "include": ["src/**/*"],
- "exclude": ["node_modules"]
- }
- compileOnSave 則是和編輯器(確切地說(shuō)是文件系統(tǒng))聯(lián)動(dòng)的配置,即是否在文件保存后進(jìn)行編譯,實(shí)際項(xiàng)目不建議使用。
除了 compilerOptions,其他也相對(duì)比較好理解。 因此接下來(lái)我只針對(duì) compilerOptions 詳細(xì)講解一番。
tsconfig 的編譯項(xiàng)
詳細(xì)全面的內(nèi)容,大家只需要參考官網(wǎng)的就好了。官網(wǎng)寫(xiě)的不僅全面,而且做了分類(lèi),非常清晰。
接下來(lái),我會(huì)根據(jù)功能分開(kāi)講幾個(gè)常用 的配置。
文件相關(guān)
常用的是以下四個(gè),由于前面已經(jīng)做了介紹,因此就不贅述了。
- exclude
- extends
- files
- include
嚴(yán)格檢查
- alwaysStrict
默認(rèn):false
首次發(fā)布版本:2.1
這個(gè)是和 ECMAScript 規(guī)范相關(guān)的,工作機(jī)制和 ES 5 的嚴(yán)格模式一樣, 并且輸出的 JS 頂部也會(huì)也會(huì)帶上 'use strict'。
- noImplicitAny(推薦打開(kāi))
默認(rèn):true
首次發(fā)布版本:-
我在 - TypeScript 類(lèi)型系統(tǒng) 中提到了如果不對(duì)變量顯式聲明類(lèi)型,那么 TypeScript 會(huì)對(duì)變量進(jìn)行類(lèi)型推導(dǎo),這當(dāng)然也有推導(dǎo)不出的情況,這個(gè)時(shí)候該變量的類(lèi)型就是 any,這個(gè)叫做隱式 any。區(qū)別于顯式 any:
- const a: any = {};
隱式 any 是 TypeScript 編譯器推斷的。
- noImplicitThis(推薦打開(kāi))
默認(rèn):true
首次發(fā)布版本:2.0
和隱式 any 類(lèi)型, 只不過(guò)這次是針對(duì)的特殊的一個(gè)關(guān)鍵字 this,也就是你需要顯式地指定 this 的類(lèi)型。
- strict(推薦打開(kāi))
默認(rèn):true
首次發(fā)布版本:2.3
實(shí)際上 strict 只是一個(gè)簡(jiǎn)寫(xiě),是多個(gè)規(guī)則的合集。 類(lèi)似于 babel 中插件(plugins)和 預(yù)設(shè)(presets)的差別。換句話說(shuō)如果你指定了 strict 為 true ,那么所有嚴(yán)格相關(guān)的規(guī)則的都會(huì)開(kāi)啟,我所講的嚴(yán)格檢查都是,還有一部分我沒(méi)有提到的。另外將來(lái)如果增加更多嚴(yán)格規(guī)則,你只要開(kāi)啟了 strict 則會(huì)自動(dòng)加進(jìn)來(lái)。
模塊解析
模塊相關(guān)
目的:allowSyntheticDefaultImports,allowUmdGlobalAccess,esModuleInterop,moduleResolution 都是為了和其他模塊化規(guī)范兼容做的。
- allowSyntheticDefaultImports
- allowUmdGlobalAccess
- esModuleInterop
- moduleResolution
還有一個(gè)配置 module,規(guī)定了項(xiàng)目的模塊化方式,選項(xiàng)有 AMD,UMD,commonjs 等。
路徑相關(guān)
目的: baseUrl,paths,rootDirs, typeRoots,types 都是為了簡(jiǎn)化路徑的拼寫(xiě)做的。
- baseUrl
這個(gè)配置是告訴 TypeScript 如何解析模塊路徑的。比如:
- import { helloWorld } from "hello/world";
- console.log(helloWorld);
這個(gè)就會(huì)從 baseUrl 下找 hello 目錄下的 world 文件。
- paths
定義類(lèi)似別名的存在,從而簡(jiǎn)化路徑的書(shū)寫(xiě)。
- rootDirs
注意是 rootDirs ,而不是 rootDir,也就是說(shuō)根目錄可以有多個(gè)。 當(dāng)你指定了多個(gè)根目錄的時(shí)候, 不同根目錄的文件可以像在一個(gè)目錄下一樣互相訪問(wèn)。
實(shí)際上也有一個(gè)叫 rootDir 的, 和 rootDirs 的區(qū)別就是其只能指定一個(gè)。
- typeRoots
- types
types 和 typeRoots 我在 - types 和 @types 是什么? 已經(jīng)講得很清楚了,這里就不多說(shuō)了。
項(xiàng)目配置
JavaScript 相關(guān)
- allowJs
默認(rèn):false
首次發(fā)布版本:1.8
顧名思義,允許在 TypeScript 項(xiàng)目中使用 JavaScript,這在從 JavaScript 遷移到 TypeScript 中是非常重要的。
- checkJs
默認(rèn):false
首次發(fā)布版本:-
和 allowJs 類(lèi)似, 只不過(guò) checkJs 會(huì)額外對(duì) JS 文件進(jìn)行校驗(yàn)。
聲明文件相關(guān)
如果 TypeScript 是將 TS 文件編譯為 JS,那么聲明文件 + JS 文件就可以反推出 TS 文件。
這兩個(gè)用來(lái)生成 .d.ts 和 .d.ts 的 sourcemap 文件。
- declaration
默認(rèn):false
首次發(fā)布版本:1.0
- declarationMap
默認(rèn):false
首次發(fā)布版本:2.9
外部庫(kù)相關(guān)
- jsx
默認(rèn):react
首次發(fā)布版本:2.2
這個(gè)是告訴 TypeScript 如何編譯 jsx 語(yǔ)法的。
- lib
默認(rèn):-
首次發(fā)布版本:2.0
lib 我在 TypeScript 類(lèi)型系統(tǒng) 中講過(guò)。 Typescript 提供了諸如 lib.d.ts 等類(lèi)型庫(kù)文件。隨著 ES 的不斷更新, JavaScript 類(lèi)型和全局變量會(huì)逐漸變多。Typescript 也是采用這種 lib 的方式來(lái)解決的。
(TypeScript 提供的部分 lib)
輸出相關(guān)
outDir 和 outFile 這兩個(gè)配置則是告訴 TypeScript 將文件生成到哪里。
- outDir
默認(rèn):和 ts 文件同目錄(且同名,只是后綴不同)
首次發(fā)布版本:-
- outFile
默認(rèn):-
首次發(fā)布版本:1.0
module 是 CommonJS 和 ES6 module 不能知道 outFile,只有是 None, System 或 AMD 才行,其會(huì)將這些模塊的文件內(nèi)容打包到全局文件內(nèi)容之后。
而 noEmit 則是控制是否輸出 JS 文件的。
- noEmit
默認(rèn):false
首次發(fā)布版本:-
如果你只希望用 TypeScript 進(jìn)行類(lèi)型檢查,不希望要它生成文件,則可以將 noEmit 設(shè)置成 true。
- target
即輸出的 JavaScript 對(duì)標(biāo)的 ECMA 規(guī)范。 比如 “target”: “es6” 就是將 es6 + 的語(yǔ)法轉(zhuǎn)換為 ES6 的 代碼。其選項(xiàng)有 ES3,ES5,ES6 等。
為什么沒(méi)有 ES4 ? ^_^
總結(jié)
- tsconfig 就是一個(gè) JSON 文件,TypeScript 會(huì)使用該文件來(lái)決定如何編譯和檢查 TypeScript 項(xiàng)目。和 babel 類(lèi)似,甚至很多配置項(xiàng)都是相通的。
- 如果一個(gè)目錄下存在一個(gè) tsconfig.json 文件,那么意味著這個(gè)目錄是 TypeScript 項(xiàng)目的根目錄。 如果你使用 tsc 編譯你的項(xiàng)目,并且沒(méi)有顯式地指定配置文件的路徑,那么 tsc 則會(huì)逐級(jí)向上搜索父目錄尋找 tsconfig.json ,這個(gè)過(guò)程類(lèi)似 node 的模塊查找機(jī)制。
- tsconfig 中最重要的恐怕就是編譯器選項(xiàng)(compilerOptions)了。如果你按照功能去記憶則會(huì)比較簡(jiǎn)單, 比如文件相關(guān)的有哪些, 嚴(yán)格檢查的有哪些,聲明文件的有哪些等等。