typeScript 配置文件該怎么寫?
點擊藍色“腦洞前端”關(guān)注我喲
加個“星標”,帶你揭開大前端的神秘面紗!
?這是腦洞前端第「104」篇原創(chuàng)文章
TypeScript 的學習資料非常多,其中也不乏很多優(yōu)秀的文章和教程。但是目前為止沒有一個我特別滿意的。原因有:
它們大多數(shù)沒有一個清晰的主線,而是按照 API 組織章節(jié)的,內(nèi)容在「邏輯上」比較零散。 大多是“講是什么,怎么用“,而不是”講為什么,講原理“。 大多數(shù)內(nèi)容比較枯燥,趣味性比較低。都是干巴巴的文字,沒有圖片,缺乏能夠引起強烈共鳴的例子。
因此我的想法是做一套不同市面上大多數(shù)的 TypeScript 學習教程。以人類認知的角度思考問題,學習 TypeScript,通過通俗易懂的例子和圖片來幫助大家建立 TypeScript 世界觀。
系列安排:
上帝視角看 TypeScript TypeScript 類型系統(tǒng) types 和 @types 是什么? TypeScript 配置文件該怎么寫?(就是本文) TypeScript 是如何與 React,Vue,Webpack 集成的? TypeScript 練習題
?目錄將來可能會有所調(diào)整。
?
注意,我的系列文章基本不會講 API,因此需要你有一定的 TypeScript 使用基礎(chǔ),推薦兩個學習資料。
深入理解 TypeScript?https://jkchao.github.io/typescript-book-chinese/ 官方文檔?https://www.typescriptlang.org/docs/home
結(jié)合這兩個資料和我的系列教程,掌握 TypeScript 指日可待。
接下來,我們通過幾個方面來從宏觀的角度來看一下 TypeScript。
前言
這篇文章是我的 TypeScript 系列的「第 5 篇」。今天我們就來看下, TypeScript 的配置文件 tsconfig.json 該如何寫。
和 package.json 一樣, 它也是一個 JSON 文件。package.json 是包描述文件,對應(yīng)的 Commonjs 規(guī)范,而 「tsconfig.json 是最終被 TypeScript Compiler 解析和使用的一個 JSON 文件」。TypeScript Compiler 用這個配置文件來決定如何對項目進行編譯。
說到編譯,不得不提一個知名選手 - babel。和 TypeScript 類似, 他們都可以將一種語法靜態(tài)編譯成另外一種語法。如果說我想編譯一個文件,我只需要告訴 babel 我的文件路徑即可。
npx?babel?script.js
有時候我想編譯整個文件夾:
npx?babel?src?--out-dir?lib
babel 也可以指定輸出目錄,指定需要忽略的文件或目錄等等, TypeScript 也是一樣!你當然可以像 babel 一樣在命令行中全部指定好,也可以將這些配置放到 tsconfig.json 中,以配置文件的形式傳遞給 TypeScript Compiler 。這就是 tsconfig.json 文件的初衷,即接受用戶輸入作為配置項。
初探 tsconfig
我們先來看一個簡單的 tsconfig 文件。
{
??"compilerOptions":?{
????"outDir":?"./built",
????"allowJs":?true,
????"target":?"es5"
??},
??"include":?["./src/**/*"]
}
如上配置做了:
讀取所有可識別的 src 目錄下的文件(通過 include)。 接受 JavaScript 做為輸入(通過 allowJs)。 生成的所有文件放在 built 目錄下(通過 outDir)。 將 JavaScript 代碼降級到低版本比如 ECMAScript 5(通過 target)。
實際項目有比這個更復雜。接下來, 我們來進一步解讀。不過在講配置項之前,我們先來看下 tsconfig.json 是如何被解析的。
tsconfig 是如何被解析的?
「如果一個目錄下存在一個 tsconfig.json 文件,那么意味著這個目錄是 TypeScript 項目的根目錄。」 如果你使用 tsc 編譯你的項目,并且沒有顯式地指定配置文件的路徑,那么 tsc 則會逐級向上搜索父目錄尋找 tsconfig.json ,這個過程類似 node 的模塊查找機制。

如圖:
在 [email protected]@uglify-js 下執(zhí)行 tsc 則會找到 配置文件 1,在 [email protected]@uglify-js/bin 下執(zhí)行 tsc 也會找到 配置文件 1 同理在 lib,node_modules 也會找到 配置文件 1 在 [email protected]@uglify-js/bin/lucifer 下執(zhí)行 tsc 則會找到 配置文件 2 在 [email protected]@uglify-js/lib/lucifer 下執(zhí)行 tsc 則會找到 配置文件 3
我在 上帝視角看 TypeScript 一種講述了 TypeScript 究竟做了什么,帶你從宏觀的角度看了一下 TypeScript。其中提到了 TypeScript 編譯器會接受文件或者文件集合作為輸入,最終轉(zhuǎn)換為 JavaScript(noEmit 為 false) 和 .d.ts(declarations 為 true)。

這里其實還少了一個點,那就是除了接受文件或者文件集合作為輸入,還會接受 tsconfig.json。tsconfig.json 的內(nèi)容決定了編譯的范圍和行為,不同的 配置可能會得到不同的輸出,或者得到不同的檢查結(jié)果。
當 tsc 找到了一個 tsconfig.json 文件,那么其規(guī)定的編譯目錄則全部會被 typescript 處理,當然也包括其依賴的文件。如果 tsc 沒有找到一個 tsconfig.json 或 tsconfig 沒有有效信息,那么 tsc 會使用默認配置。比如 tsconfig 是一個空的就沒有有效信息:
{}
?tsconfig 的全部屬性,以及屬性的默認值可以在這里找到:http://json.schemastore.org/tsconfig
?
總結(jié)一下 tsc 解析 tsconfig.json 的邏輯。
如果命令行指定了配置選項或者指定了配置文件的路徑,那么直接會讀取。 如果正確,則將其和默認配置合并(如果有 extends 字段,也會一起合并),將合并后的配置傳遞給 TypeScript 編譯器并開始編譯。 否則拋出錯誤 根據(jù) tsconfig json schema 校驗是否格式正確。 否則,會從當前目錄查找 tsconfig.json 文件, 如果找不到則逐層向上搜索父目錄。 如果正確,則將其和默認配置合并(如果有 extends 字段,也會一起合并),將合并后的配置傳遞給 TypeScript 編譯器并開始編譯。 否則拋出錯誤 如果找到了則會去根據(jù) tsconfig json schema 校驗是否格式正確。 否則,始終找不到則直接使用默認配置
tsconfig 的頂層屬性
tsconfig 的頂層屬性(Top Level)不多,主要有:「compilerOptions, files, include, exclude,extends,compileOnSave」等。
compilerOptions 是重頭戲,其屬性也是最多的,我們的項目也是對這個定制比較多,這個我后面會重點講。 files 則是你需要編譯的文件 exclude 則是你不需要編譯的文件目錄(支持 glob) include 是你需要編譯的文件目錄(支持 glob) extends 就是繼承另外一個配置文件,TypeScript 會對其進行合并,多項目公共配置有用。你也可以直接繼承社區(qū)的“最佳實踐”,比如:
{
??"extends":?"@tsconfig/node12/tsconfig.json",
??"compilerOptions":?{},
??"include":?["src/**/*"],
??"exclude":?["node_modules"]
}
compileOnSave 則是和編輯器(確切地說是文件系統(tǒng))聯(lián)動的配置,即是否在文件保存后進行編譯,實際項目不建議使用。
除了 compilerOptions,其他也相對比較好理解。因此接下來我只針對 compilerOptions 詳細講解一番。
tsconfig 的編譯項
詳細全面的內(nèi)容,大家只需要參考官網(wǎng)[1]的就好了。官網(wǎng)寫的不僅全面,而且做了分類,非常清晰。
接下來,我會根據(jù)功能分開講幾個「常用」 的配置。
文件相關(guān)
常用的是以下四個,由于前面已經(jīng)做了介紹,因此就不贅述了。
exclude extends files include
嚴格檢查
alwaysStrict
默認:false
首次發(fā)布版本:2.1
這個是和 ECMAScript 規(guī)范相關(guān)的,工作機制和 ES 5 的嚴格模式一樣, 并且輸出的 JS 頂部也會也會帶上 'use strict'。
noImplicitAny(推薦打開)
默認:true
首次發(fā)布版本:-
我在 - TypeScript 類型系統(tǒng) 中提到了如果不對變量顯式聲明類型,那么 TypeScript 會對變量進行類型推導,這當然也有推導不出的情況,這個時候該變量的類型就是 any,這個叫做隱式 any。區(qū)別于顯式 any:
const?a:?any?=?{};
隱式 any 是 TypeScript 編譯器推斷的。
noImplicitThis(推薦打開)
默認:true
首次發(fā)布版本:2.0
和隱式 any 類型, 只不過這次是針對的特殊的一個關(guān)鍵字 this,也就是你需要顯式地指定 this 的類型。
strict(推薦打開)
默認:true
首次發(fā)布版本:2.3
實際上 strict 只是一個簡寫,是多個規(guī)則的合集。類似于 babel 中插件(plugins)和 預設(shè)(presets)的差別。換句話說如果你指定了 strict 為 true ,那么所有嚴格相關(guān)的規(guī)則的都會開啟,我所講的「嚴格檢查」都是,還有一部分我沒有提到的。另外將來如果增加更多嚴格規(guī)則,你只要開啟了 strict 則會自動加進來。
模塊解析
模塊相關(guān)
目的:「allowSyntheticDefaultImports,allowUmdGlobalAccess,esModuleInterop,moduleResolution 都是為了和其他模塊化規(guī)范兼容做的。」
allowSyntheticDefaultImports allowUmdGlobalAccess esModuleInterop moduleResolution
還有一個配置 「module」,規(guī)定了項目的模塊化方式,選項有 AMD,UMD,commonjs 等。
路徑相關(guān)
目的:「baseUrl,paths,rootDirs, typeRoots,types 都是為了簡化路徑的拼寫做的。」
baseUrl
這個配置是告訴 TypeScript 如何解析模塊路徑的。比如:
import?{?helloWorld?}?from?"hello/world";
console.log(helloWorld);
這個就會從 baseUrl 下找 hello 目錄下的 world 文件。
paths
定義類似別名的存在,從而簡化路徑的書寫。
rootDirs
注意是 rootDirs ,而不是 rootDir,也就是說根目錄可以有多個。當你指定了多個根目錄的時候, 不同根目錄的文件可以像在一個目錄下一樣互相訪問。
?實際上也有一個叫 rootDir 的, 和 rootDirs 的區(qū)別就是其只能指定一個。
?
typeRoots types
types 和 typeRoots 我在 - types 和 @types 是什么? 已經(jīng)講得很清楚了,這里就不多說了。
項目配置
JavaScript 相關(guān)
allowJs
默認:false
首次發(fā)布版本:1.8
顧名思義,允許在 TypeScript 項目中使用 JavaScript,這在從 JavaScript 遷移到 TypeScript 中是非常重要的。
checkJs
默認:false
首次發(fā)布版本:-
和 allowJs 類似, 只不過 checkJs 會額外對 JS 文件進行校驗。
聲明文件相關(guān)
如果 TypeScript 是將 TS 文件編譯為 JS,那么聲明文件 + JS 文件就可以反推出 TS 文件。
這兩個用來生成 .d.ts 和 .d.ts 的 sourcemap 文件。
declaration
默認:false
首次發(fā)布版本:1.0
declarationMap
默認:false
首次發(fā)布版本:2.9
外部庫相關(guān)
jsx
默認:react
首次發(fā)布版本:2.2
這個是告訴 TypeScript 如何編譯 jsx 語法的。
lib
默認:-
首次發(fā)布版本:2.0
lib 我在 TypeScript 類型系統(tǒng) 中講過。Typescript 提供了諸如 lib.d.ts 等類型庫文件。隨著 ES 的不斷更新, JavaScript 類型和全局變量會逐漸變多。Typescript 也是采用這種 lib 的方式來解決的。

(TypeScript 提供的部分 lib)
輸出相關(guān)
outDir 和 outFile 這兩個配置則是告訴 TypeScript 將文件生成到哪里。
outDir
默認:和 ts 文件同目錄(且同名,只是后綴不同)
首次發(fā)布版本:-
outFile
默認:-
首次發(fā)布版本:1.0
module 是 CommonJS 和 ES6 module 不能知道 outFile,只有是 None, System 或 AMD 才行,其會將這些模塊的文件內(nèi)容打包到全局文件內(nèi)容之后。
而 noEmit 則是控制是否輸出 JS 文件的。
noEmit
默認:false
首次發(fā)布版本:-
如果你只希望用 TypeScript 進行類型檢查,不希望要它生成文件,則可以將 noEmit 設(shè)置成 true。
target
即輸出的 JavaScript 對標的 ECMA 規(guī)范。比如 “target”: “es6” 就是將 es6 + 的語法轉(zhuǎn)換為 ES6 的 代碼。其選項有 ES3,ES5,ES6 等。
?為什么沒有 ES4 ?^_^
?
總結(jié)
tsconfig 就是一個 JSON 文件,TypeScript 會使用該文件來決定如何編譯和檢查 TypeScript 項目。和 babel 類似,甚至很多配置項都是相通的。
如果一個目錄下存在一個 tsconfig.json 文件,那么意味著這個目錄是 TypeScript 項目的根目錄。如果你使用 tsc 編譯你的項目,并且沒有顯式地指定配置文件的路徑,那么 tsc 則會逐級向上搜索父目錄尋找 tsconfig.json ,這個過程類似 node 的模塊查找機制。
tsconfig 中最重要的恐怕就是編譯器選項(compilerOptions)了。如果你按照功能去記憶則會比較簡單, 比如文件相關(guān)的有哪些, 嚴格檢查的有哪些,聲明文件的有哪些等等。
參考
typescriptlang's tsconfig?https://www.typescriptlang.org/tsconfig
推薦閱讀
1、力扣刷題插件
2、你不知道的 TypeScript 泛型(萬字長文,建議收藏)
4、immutablejs 是如何優(yōu)化我們的代碼的?
6、想去力扣當前端,TypeScript 需要掌握到什么程度?
?關(guān)注加加,星標加加~
?
如果覺得文章不錯,幫忙點個在看唄
Reference
官網(wǎng)-tsconfig: https://www.typescriptlang.org/tsconfig
