熟悉 Typescript 配置選項是 TS 專案開發的最基本要求。
TS 使用 tsconfig.json
作為其配置檔案,它主要包含兩塊內容:
- 指定待編譯的檔案
- 定義編譯選項
另外,一般來說,tsconfig.json
檔案所處的路徑就是當前 TS 專案的根路徑。
基本用法
TS 的編譯命令為 tsc
,當我們在命令列中直接輸入 tsc
時,會列印出如下的使用說明:
$ tsc
Version 2.7.2
Syntax: tsc [options] [file ...]
Examples: tsc hello.ts
tsc --outFile file.js file.ts
tsc @args.txt
Options:
-h, --help Print this message.
--all Show all compiler options.
-v, --version Print the compiler`s version.
...
如果僅僅是編譯少量的檔案,我們可以直接使用 tsc
,通過其選項來設定編譯配置,如:
tsc --outFile file.js --target es3 --module commonjs file.ts
但如果是編譯整個專案的話,最推薦的做法是使用 tsconfig.json
檔案,這樣就不用每次編譯時都還得手動敲配置,而且也便於團隊協作。
以下是讓 tsc
使用 tsconfig.json
的兩種方式:
- 不顯式指定
tsconfig.json
,此時,編譯器會從當前路徑開始尋找tsconfig.json
檔案,如果沒有找到,則繼續往上級路徑逐步尋找,直到找到為止 - 通過
--project
(或縮寫-p
)指定一個包含tsconfig.json
的路徑,或者包含配置資訊的.json
檔案路徑
注意,tsc
的命令列選項具有優先順序,會覆蓋 tsconfig.json
中的同名選項。
使用示例
下面是一個簡單的配置示例:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true
},
"files": [
"app.ts",
"foo.ts",
]
}
其中,compilerOptions
用來配置編譯選項,files
用來指定待編譯檔案。
這裡的待編譯檔案是指入口檔案,任何被入口檔案依賴的檔案,比如 foo.ts
依賴 bar.ts
,那這裡並不需要寫上 bar.ts
,編譯器會自動把所有的依賴檔案納為編譯物件。
也可以使用 include
和 exclude
來指定和排除待編譯檔案:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
所以,總結一下,指定待編譯檔案有兩種方式:
- 使用
files
屬性 - 使用
include
和exclude
屬性
開發者可以按照自己的喜好使用其中任意一種。但它們不是互斥的,在某些情況下兩者搭配起來使用效果更佳。
配置說明
檔案指定
files
屬性是一個陣列,陣列元素可以是相對檔案路徑和絕對檔案路徑。
include
和 exclude
屬性也是一個陣列,但陣列元素是類似 glob
的檔案模式。它支援的 glob
萬用字元包括:
-
*
:匹配 0 或多個字元(注意:不含路徑分隔符) -
?
:匹配任意單個字元(注意:不含路徑分隔符) -
**/
:遞迴匹配任何子路徑
在繼續說明之前,有必要先了解下在編譯器眼裡什麼樣的檔案才算是 TS 檔案。
TS 檔案指擴充名為 .ts
、.tsx
或 .d.ts
的檔案。如果開啟了 allowJs
選項,那 .js
和 .jsx
檔案也屬於 TS 檔案。
如果僅僅包含一個 *
或者 .*
,那麼只有TS 檔案才會被包含。
如果 files
和 include
都未設定,那麼除了 exclude
排除的檔案,編譯器會預設包含路徑下的所有 TS 檔案。
如果同時設定 files
和 include
,那麼編譯器會把兩者指定的檔案都引入。
如果未設定 exclude
,那其預設值為 node_modules
、bower_components
、jspm_packages
和編譯選項 outDir
指定的路徑。
exclude
只對 include
有效,對 files
無效。即 files
指定的檔案如果同時被 exclude
排除,那麼該檔案仍然會被編譯器引入。
前面提到,任何被 files
或 include
引入的檔案的依賴會被自動引入。
反過來,如果 B.ts
被 A.ts
依賴,那麼 B.ts
不能被 exclude
排除,除非 A.ts
也被排除了。
有一點要注意的是,編譯器不會引入疑似為輸出的檔案。比如,如果引入的檔案中包含 index.ts
,那麼 index.d.ts
和 index.js
就會被排除。通常來說,只有擴充名不一樣的檔案命名法是不推薦的。
tsconfig.json
也可以為空檔案,這種情況下會使用預設的編譯選項來編譯所有預設引入的檔案。
編譯選項
常用選項
選項欄位 | 型別 | 預設值 | 說明 |
---|---|---|---|
allowJs |
boolean |
false |
允許編譯 JS 檔案 |
checkJs |
boolean |
false |
報告 JS 檔案中存在的型別錯誤需要配合 allowJs 使用 |
declaration |
boolean |
false |
生成對應的 .d.ts 檔案 |
declarationDir |
string |
- |
生成的 .d.ts 檔案存放路徑預設與 .ts 檔案相同 |
experimentalDecorators |
boolean |
false |
啟用實驗功能-ES 裝飾器 |
jsx |
string |
Preserve |
在 .tsx 中支援 JSX :React 或 Preserve ,詳細說明
|
jsxFactory |
string |
React.createElement |
jsx 設定為 React 時使用的建立函式 |
lib |
string[] |
- |
編譯時引入的 ES 功能庫,包括:es5 、es6 、es7 、dom 等。如果未設定,則預設為: target 為 es5 時: ["dom", "es5", "scripthost"] target 為 es6 時: ["dom", "es6", "dom.iterable", "scripthost"]
|
module |
string |
target === "es3" or "es5" ? "commonjs" : "es6"
|
生成的模組形式:none 、commonjs 、amd 、system 、umd 、es6 、es2015 或 esnext 只有 amd 和 system 能和 outFile 一起使用 target 為 es5 或更低時可用 es6 和 es2015
|
moduleResolution |
string |
module === "amd" or "system" or "es6" ? "classic" : "node"
|
模組解析方式,詳細說明 |
noImplicitAny |
boolean |
false |
存在隱式 any 時拋錯 |
noImplicitReturns |
boolean |
false |
不存在 return 時拋錯 |
noImplicitThis |
boolean |
false |
this 可能為 any 時拋錯 |
outDir |
string |
- |
編譯生成的檔案存放路徑預設與 .ts 檔案相同 |
sourceMap |
boolean |
false |
生成 .map 檔案 |
target |
string |
es3 |
生成 .js 檔案版本 |
型別相關
型別相關的選項包括 typeRoots
和 types
。
有一個普遍的誤解,以為這兩個選項適用於所有的型別宣告檔案,包括使用者自定義的宣告檔案。其實不然。
這兩個選項只對通過 npm 安裝的宣告模組有效,使用者自定義的型別宣告檔案與它們沒有任何關係。
宣告模組通常會包含一個 index.d.ts
檔案,或者其 package.json
設定了 types
欄位。
預設的,所有位於 node_modules/@types
路徑下的模組都會引入到編譯器。
具體來說是,./node_modules/@types
、../node_modules/@types
、../../node_modules/@types
等等。
typeRoots
用來指定預設的型別宣告檔案查詢路徑,預設為 node_modules/@types
。比如:
{
"compilerOptions": {
"typeRoots": ["./typings"]
}
}
上面的配置會自動引入 ./typings
下的所有 TS 型別宣告模組,而不是 ./node_modules/@types
下的模組。
如果不希望自動引入 typeRoots
指定路徑下的所有宣告模組,那可以使用 types
指定自動引入哪些模組。比如:
{
"compilerOptions": {
"types" : ["node", "lodash", "express"]
}
}
只會引入 node
、 lodash
和 express
三個宣告模組,其它的宣告模組則不會被自動引入。
如果 types
被設定為 []
,那麼將不會自動引入任何宣告模組。此時,如果想使用宣告模組,只能在程式碼中手動引入了。
請記住,自動引入只對包含全域性宣告的模組有效。比如 jQuery
,我們不用手動 import
或者 ///<reference/>
即可在任何檔案中使用 $
的型別。再比如,對於 import `foo`
,編譯器會分別在 node_modules
和 node_modules/@types
檔案下查詢 foo
模組和宣告模組。
基於此,如果想讓自定義宣告的型別不需要手動引入就可以在任何地方使用,可以將其宣告為全域性宣告 global
,然後讓 files
或者 include
包含即可。
比如:
declare global {
const graphql: (query: TemplateStringsArray) => void;
namespace Gatsby {
interface ComponentProps {
children: () => React.ReactNode,
data: RootQueryType
}
}
}
這樣的話,就可以在任何地方直接使用 graphql
和 Gatsby
對應的型別了。
配置複用
可以使用 extends
來實現配置複用,即一個配置檔案可以繼承另一個檔案的配置屬性。
比如,建立一個基礎的配置檔案 configs/base.json
:
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true
}
}
然後,tsconfig.json
就可以引用這個檔案的配置了:
{
"extends": "./configs/base",
"files": [
"main.ts",
"supplemental.ts"
]
}
這種繼承有兩種特點:
- 繼承者中的同名配置會覆蓋被繼承者
- 所有相對路徑都被解析為其所在檔案的路徑