本篇主要介紹 TypeScript 中的 tsconfig.json 檔案的作用以及配置引數.主要介紹檔案選項和編譯選項兩部分.
如果一個目錄下存在一個 tsconfig.json
檔案,那麼它意味著這個目錄是 TypeScript 專案的根目錄。tsconfig.json
檔案中指定了用來編譯這個專案的根檔案和編譯選項。 一個專案可以通過以下方式之一來編譯:
- 不帶任何輸入檔案的情況下呼叫
tsc
,編譯器會從當前目錄開始去查詢tsconfig.json文
件,逐級向上搜尋父目錄。 - 不帶任何輸入檔案的情況下呼叫
tsc
,且使用命令列引數--project
(或-p
)指定一個包含tsconfig.json
檔案的目錄。
當命令列上指定了輸入檔案時,tsconfig.json檔案會被忽略。
檔案選項
files
它的含義是編譯器需要編譯的相對或絕對檔案路徑的單個檔案列表。
{
"files": [
"src/index.ts"
]
}
複製程式碼
這時執行 tsc
命令,編譯器會編譯 src/index.ts
檔案。
include
它的含義是編譯器需要編譯的檔案或者目錄。
{
"include": [
"src"
]
}
複製程式碼
這時執行 tsc
命令,編譯器會編譯 src
目錄下的所有 ts
檔案。
exclude
它的含義是編譯器需要排除的檔案或者目錄。預設會排除 node_modules
目錄下的所有檔案。
{
"exclude": [
"src/lib"
]
}
複製程式碼
-
- 如果
files
和includes
都沒有指定,編譯器預設包含當前目錄下所有的ts
檔案。(.ts
、.d.ts
、.tsx
)
- 如果
-
- 如果
exclude
存在,exclude
配置優先順序高於files
和includes
配置
- 如果
-
exclude
和includes
配置支援 glob 萬用字元:*
、?
、**
extends
我們可以把一些配置抽離出一個配置檔案,再 tsconfig.json
檔案引入,方便以後管理與維護。
// tsconfig.json
{
"extends": "./base.json"
}
複製程式碼
在主配置檔案中,設定檔案選項會覆蓋調繼承檔案中的相同的配置項。
compileOnSave
它可以讓 IDE 在儲存檔案時,編譯器自動編譯。
{
"compileOnSave": true
}
複製程式碼
目前只有個別 IDE 支援。
編譯選項
大致配置如下所示:
{
"compilerOptions": {
"incremental": true, // 增量編譯
"tsBuildInfoFile": "./buildFile", // 增量編譯檔案的儲存位置
"diagnostics": true, // 列印編譯資訊
"target": "es5", // 目標語言的版本
"module": "commonjs", // 生成程式碼的模組標準
"outFile": "./app.js", // 將多個相互依賴的檔案生成一個檔案,可以用在 AMD 模組中
"lib": [], // TS 需要引用的庫,即宣告檔案,es5 預設 "dom", "es5", "scripthost"
"allowJs": true, // 允許編譯 JS 檔案(js、jsx)
"checkJs": true, // 允許在 JS 檔案中報錯,通常與 allowJS 一起使用
"outDir": "./out", // 指定輸出目錄
"rootDir": "./", // 指定輸入檔案目錄(用於輸出)
"declaration": true, // 生成宣告檔案
"declarationDir": "./d", // 宣告檔案的路徑
"emitDeclarationOnly": true, // 只生成宣告檔案
"sourceMap": true, // 生成目標檔案的 sourceMap
"inlineSourceMap": true, // 生成目標檔案的 inline sourceMap
"declarationMap": true, // 生成宣告檔案的 sourceMap
"typeRoots": [], // 宣告檔案目錄,預設 node_modules/@types
"types": [], // 宣告檔案包
"removeComments": true, // 刪除註釋
"noEmit": true, // 不輸出檔案
"noEmitOnError": true, // 發生錯誤時不輸出檔案
"noEmitHelpers": true, // 不生成 helper 函式,需額外安裝 ts-helpers
"importHelpers": true, // 通過 tslib 引入 helper 函式,檔案必須是模組
"downlevelIteration": true, // 降級遍歷器的實現(es3/5)
"strict": true, // 開啟所有嚴格的型別檢查
"alwaysStrict": false, // 在程式碼中注入 "use strict";
"noImplicitAny": false, // 不允許隱式的 any 型別
"strictNullChecks": false, // 不允許把 null、undefined 賦值給其他型別變數
"strictFunctionTypes": false, // 不允許函式引數雙向協變
"strictPropertyInitialization": false, // 類的例項屬性必須初始化
"strictBindCallApply": false, // 嚴格的 bind/call/apply 檢查
"noImplicitThis": false, // 不允許 this 有隱式的 any 型別
"noUnusedLocals": true, // 檢查只宣告,未使用的區域性變數
"noUnusedParameters": true, // 檢查未使用的函式引數
"noFallthroughCasesInSwitch": true, // 防止 switch 語句貫穿
"noImplicitReturns": true, // 每個分支都要有返回值
"esModuleInterop": true, // 允許 export = 匯出,由import from 匯入
"allowUmdGlobalAccess": true, // 允許在模組中訪問 UMD 全域性變數
"moduleResolution": "node", // 模組解析策略
"baseUrl": "./", // 解析非相對模組的基地址
"paths": { // 路徑對映,相對於 baseUrl
"jquery": ["node_modules/jquery/dist/jquery.slim.min.js"]
},
"rootDirs": ["src", "util"], // 將多個目錄放在一個虛擬目錄下,用於執行時
"listEmittedFiles": true, // 列印輸出的檔案
"listFiles": true, // 列印編譯的檔案(包括引用的宣告檔案)
}
}
複製程式碼
接下來,我們會逐個分析上面的配置項。
incremental
它的含義是增量編譯,TypeScript 編譯器在第一次編譯後會生成一個可以編譯資訊的檔案,在之後的編譯之後會根據這個檔案提高編譯的速度。該檔案預設會在根目錄下名稱為 tsconfig.tsbuildinfo
:
{
"program": {
"fileInfos": {
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.d.ts": {
"version": "49ff9798f592c8b7e628fd881401e68810c1b3589ecd7a41b32b3c287374cde0",
"signature": "49ff9798f592c8b7e628fd881401e68810c1b3589ecd7a41b32b3c287374cde0"
},
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.es5.d.ts": {
"version": "ff5688d6b2fcfef06842a395d7ff4d5730d45b724d4c48913118c889829052a1",
"signature": "ff5688d6b2fcfef06842a395d7ff4d5730d45b724d4c48913118c889829052a1"
},
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.dom.d.ts": {
"version": "2d53f3741e5a4f78a90f623387d71a1cc809bb258f10cdaec034b67cbf71022f",
"signature": "2d53f3741e5a4f78a90f623387d71a1cc809bb258f10cdaec034b67cbf71022f"
},
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.webworker.importscripts.d.ts": {
"version": "fe4e59403e34c7ff747abe4ff6abbc7718229556d7c1a5b93473fb53156c913b",
"signature": "fe4e59403e34c7ff747abe4ff6abbc7718229556d7c1a5b93473fb53156c913b"
},
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.scripthost.d.ts": {
"version": "b9faa17292f17d2ad75e34fac77dd63a6403af1dba02d39cd0cbb9ffdf3de8b9",
"signature": "b9faa17292f17d2ad75e34fac77dd63a6403af1dba02d39cd0cbb9ffdf3de8b9"
},
"./src/index.ts": {
"version": "a0e2a405f15ab7f6218e22c622acc2706d51eae2aa90f302f81f68628e22cd55",
"signature": "ec8f4696ee1308e5fbc9f50626f5677f0f15bd7c228311cbcc0669233461fa1d"
}
},
"options": {
"incremental": true,
"configFilePath": "./tsconfig.json"
},
"referencedMap": {},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.d.ts",
"./src/index.ts",
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.es5.d.ts",
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.dom.d.ts",
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.webworker.importscripts.d.ts",
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.scripthost.d.ts"
]
},
"version": "3.6.2"
}
複製程式碼
tsBuildInfoFile
可以修改增量編譯檔案的儲存資料夾和檔名
diagnostics
列印編譯資訊。
Files: 6
Lines: 24817
Nodes: 111372
Identifiers: 41045
Symbols: 27914
Types: 8268
Memory used: 68338K
I/O read: 0.01s
I/O write: 0.00s
Parse time: 0.42s
Bind time: 0.23s
Check time: 1.13s
Emit time: 0.02s
Total time: 1.80s
複製程式碼
target
設定目標語言的版本,可設定為 ES3
、ES5
和 ES2015
等等,預設為 ES3
。
module
設定生成程式碼的模組標準,可以設定為 CommonJS
、AMD
和 UMD
等等。
outFile
將多個相互依賴的檔案生成一個檔案,可以用在 AMD 模組中。
我們建立兩個檔案,分別為 index.ts
和 amd.ts
,如下所示:
// ./src/index.ts
import a = require('./amd')
let str: string = 'abc'
複製程式碼
// ./src/amd.ts
let amd: number = 0
export = amd
複製程式碼
index.ts
引入 amd.ts
,我們再設定一下 tsconfig.json
檔案。
{
"compilerOptions": {
"module": "amd",
"outFile": "./app.js"
}
}
複製程式碼
然後在命令列執行 tsc
命令,編譯器會將兩個 ts
檔案合併編譯成一個 app.js
檔案。
define("amd", ["require", "exports"], function (require, exports) {
"use strict";
var amd = 0;
return amd;
});
define("index", ["require", "exports"], function (require, exports) {
"use strict";
exports.__esModule = true;
var str = 'abc';
});
複製程式碼
lib
指定 ts
需要引用的庫,即宣告檔案,若 target
設定為 es5
時,lib
預設為 ["dom", "es5", "scripthost"]
。
例如,我們想在 ts
中使用 es2019 的方法。可以在 lib
配置裡新增 es2019
。
allowJs
允許編譯器編譯 JS 檔案(js、jsx)。
checkJs
允許在 JS 檔案中報錯,通常與 allowJS 一起使用。
outDir
指定輸出目錄
rootDir
指定輸入檔案目錄
declaration
編譯器編譯時,允許生成宣告檔案(.d.ts
)。
declarationDir
指定宣告檔案的生成的目錄。
emitDeclarationOnly
編譯器編譯時,只允許生成宣告檔案。
sourceMap
編譯器編譯時,生成目標檔案的 sourceMap 檔案。
inlineSourceMap
編譯器編譯時,將 sourceMap 生成在 js
檔案中。
declarationMap
編譯器編譯時,生成宣告檔案的 sourceMap。
typeRoots
設定宣告檔案目錄,預設 node_modules/@types
types
這是宣告檔案包,如果設定了某一個宣告檔案,那麼編譯器只會載入這個宣告檔案。
removeComments
是否刪除註釋
noEmit
執行 tsc
不會輸出任何檔案
noEmitOnError
發生錯誤時不輸出檔案
noEmitHelpers
設定為 true
時,不生成 helper
函式。先看下面示例:
class B {}
class A extends B {}
export = A
複製程式碼
我們建立了一個模組。然後在控制檯執行 tsc
,下面就是編譯後的結果:
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var B = /** @class */ (function () {
function B() {
}
return B;
}());
var A = /** @class */ (function (_super) {
__extends(A, _super);
function A() {
return _super !== null && _super.apply(this, arguments) || this;
}
return A;
}(B));
module.exports = A;
複製程式碼
編譯器會自動生成 __extends
。
如果我們將 noEmitHelpers 這個配置設定為 true
之後。編譯後的結果如下:
"use strict";
var B = /** @class */ (function () {
function B() {
}
return B;
}());
var A = /** @class */ (function (_super) {
__extends(A, _super);
function A() {
return _super !== null && _super.apply(this, arguments) || this;
}
return A;
}(B));
module.exports = A;
複製程式碼
上面的編譯後的結果中 __extends
未定義。ts
已經為開發者定義了一個配置項,方便解決該問題。 就是接下來要介紹的配置 importHelpers
。
importHelpers
通過 tslib
引入 helper
函式,檔案必須是模組。編譯結果如下:
"use strict";
var tslib_1 = require("tslib");
var B = /** @class */ (function () {
function B() {
}
return B;
}());
var A = /** @class */ (function (_super) {
tslib_1.__extends(A, _super);
function A() {
return _super !== null && _super.apply(this, arguments) || this;
}
return A;
}(B));
module.exports = A;
複製程式碼
若提示 tslib
未找到時,可以手動安裝它。
downlevelIteration
降級遍歷器的實現,下面是一個 es6
語法:
let a = [1, 2, 3]
let b = [4, ...a]
複製程式碼
我們開啟這項配置,進行編譯後結果如下:
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
var a = [1, 2, 3];
var b = __spread([4], a);
複製程式碼
會生成兩個 helper
函式。
strict
表示開啟所有嚴格的型別檢查,若 strict
為 true,alwaysStrict
、noImplicitAny
、strictNullChecks
、strictFunctionTypes
、strictPropertyInitialization
、strictBindCallApply
和 noImplicitThis
選項預設都為 true。
alwaysStrict
在程式碼中注入 use strict
。
noImplicitAny
不允許隱式的 any
型別。
strictNullChecks
不允許把 null
、undefined
賦值給其他型別變數。
strictFunctionTypes
不允許函式引數雙向協變。
strictPropertyInitialization
類的例項屬性必須初始化。
strictBindCallApply
嚴格的 bind
、call
、apply
檢查。
function add (a: number, b: number) {
return a + b
}
add.call(undefined, 1, '2')
// Error: Argument of type '"2"' is not assignable to parameter of type 'number'.
複製程式碼
noImplicitThis
不允許 this
有隱式的 any
型別。
class A {
name: string = 'abc'
getName () {
return function () {
console.log(this.name)
}
}
}
// Error: 'this' implicitly has type 'any' because it does not have a type annotation.
複製程式碼
noUnusedLocals
檢查只宣告,未使用的區域性變數
noUnusedParameters
檢查未使用的函式引數
noFallthroughCasesInSwitch
防止 switch 語句貫穿
noImplicitReturns
每個分支都要有返回值
esModuleInterop
允許 export =
方式匯出,也可以用 import =
的方式匯入。
allowUmdGlobalAccess
允許在模組中訪問 UMD 全域性變數
moduleResolution
模組解析策略,這裡提供兩種解析策略 node
和 classic
,ts
預設使用 node
解析策略。
- classic 模組解析策略
適用於 AMD
、System
、ES2015
如果一個模組使用相對方式匯入時,ts
就會依次解析同級目錄 .ts
、.d.ts
檔案。
// /root/src/moduleA.ts
import { b } from './moduleB'
/**
* /root/src/moduleB.ts
* /root/src/moduleB.d.ts
*/
複製程式碼
如果使用非相對方式匯入時如下, ts
會從當前目錄的 node_modules
目錄裡查詢,如果未找到,會依次向上級目錄查詢。
// /root/src/moduleA.ts
import { b } from 'moduleB'
/**
* /root/src/node_modules/moduleB.ts
* /root/src/node_modules/moduleB.d.ts
*
* /root/node_modules/moduleB.ts
* /root/node_modules/moduleB.d.ts
*
* /node_modules/moduleB.ts
* /node_modules/moduleB.d.ts
*/
複製程式碼
- node 模組解析策略
使用相對方式匯入
// /root/src/moduleA.ts
import { b } from './moduleB'
/**
* /root/src/moduleB.ts
* /root/src/moduleB.tsx
* /root/src/moduleB.d.ts
* /root/src/moduleB/package.json ( types 屬性)
* /root/src/moduleB/index.ts
* /root/src/moduleB/index.tsx
* /root/src/moduleB/index.d.ts
*/
複製程式碼
使用非相對方式匯入
// /root/src/moduleA.ts
import { b } from 'moduleB'
/**
* /root/src/node_modules/moduleB.ts
* /root/src/node_modules/moduleB.tsx
* /root/src/node_modules/moduleB.d.ts
* /root/src/node_modules/package.json ( types 屬性)
* /root/src/node_modules/index.ts
* /root/src/node_modules/index.tsx
* /root/src/node_modules/index.d.ts
*
* 依次向上目錄查詢
*/
複製程式碼
baseUrl
解析非相對模組的基地址,預設為當前目錄
paths
路徑對映,相對於 baseUrl。比如示例中我們想引入 jquery 精簡版本,可以制定它的相對路徑。
rootDirs
將多個目錄放在一個虛擬目錄下,用於執行時。
比如 我們建立量以下兩個檔案。
// /util/a.ts
let a: string = 'A'
export = a
複製程式碼
// /src/index.ts
import a from './a'
複製程式碼
注意在引入 a
時,是引入的當前目錄。因為當 rootDirs
設定了 src
和 util
目錄時,編譯器預設它們屬於同級目錄。
listEmittedFiles
列印輸出的檔案。
listFiles
列印編譯的檔案,包括引用的宣告檔案。
結語
想要了解更多關於 TypeScript 相關知識,可以點選TypeScript開發教程收藏並閱讀.