基於typescript的專案的根目錄下都會有一個檔案(tsconfig.json
), 這個檔案主要用來控制typescript編譯器(tsc, typescript compiler)的一些行為, 比如指定哪些檔案需要讓tsc來編譯, 哪些檔案不想讓tsc進行編譯之類的.
angular專案的tsconfig.json
檔案
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"module": "es2020",
"lib": [
"es2018",
"dom"
]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictTemplates": true
}
}
這其中angularCompilerOptions
顧名思義是angular專用的, 不在本文討論範圍.
include
: 指定要編譯哪些檔案, 比如只需要編譯<project-dir>/src
目錄下的.ts原始碼檔案
{
"compilerOptions": {
...
},
include: ["./src/**/*", "./demo/**/*.tsx?"]
}
上面的include設定用到了兩個萬用字元: **/
, *
**/
表示匹配任何子路徑, 包括目錄分隔符/
也會被它匹配, 所以用來這個萬用字元後, 目錄下有多少子目錄都會被匹配到
*
表示匹配除了目錄分隔符(/
)外的任何長度的字串
?
表示匹配一個除檔案分隔符(/
)外的任一字元
顯然./src/**/*
即表示匹配src
資料夾下的任何子資料夾的任何檔案; 而./demo/**/*.tsx?
即表示匹配demo
目錄下任何子目錄下的任意以.ts
或.tsx
結尾的檔案
include其實就是一個白名單, 在這個白名單裡被匹配到的檔案才會被tsc處理編譯
相對於include
是作為白名單的設定, exclude
選項就是一個黑名單了, 它的值和include一樣是一個路徑名字串陣列, 最常見的用處就是用來排除掉node_modules
目錄下的檔案
{
"compilerOptions": {
...
},
include: ["./src/**/*", "./demo/**/*.tsx?"],
exclude: ["node_modules/**/*"]
}
當然也可以用exclude
排除掉include
裡面包含到的檔案
有些情況即使exclude了某些檔案後, 編譯後的程式碼中可能仍然包含被
exclude
了的內容, 比如通過import
匯入了被exclude
了的node_modules
資料夾, 此時tsc仍然會去處理被exclude了的檔案, 這一點應該不難理解
files
設定的作用類似include
, 也是一個白名單路徑陣列, 不同在於它不能使用萬用字元, 而必須使用精確的檔案路徑(可以是相對路徑), 比如如果專案只有一個入口檔案, 那麼就可以使用在只用files
設定這個檔案的路徑, 然後其他的檔案都通過index.ts
來import
{
"compilerOptions": {
...
},
// include: ["./src/**/*", "./demo/**/*.tsx?"],
// exclude: ["node_modules/**/*"]
files: ['./src/index.ts']
}
extends
用於在一個tsconfig.json
檔案中擴充套件其他tsconfig.json
檔案, 比如angular專案中有三個tsconfig組態檔: tsconfig.json
, tsconfig.spec.json
, tsconfig.app.json
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"module": "es2020",
"lib": [
"es2018",
"dom"
]
},
...
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": [
"src/main.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.d.ts"
]
}
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
...
"files": [
"src/test.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
從命名和檔案內容上即可看出之所以這麼做是為了針對測試檔案.spec.ts
和普通.ts
檔案在使用不同的設定時又能共用他們相同部分的設定, 達到避免重複的目的
表示是否允許程式碼中出現永遠無法被執行到的程式碼, 可選值是undefined
, false
, true
{
"compilerOptions": {
"allowUnreachableCode": false
...
},
...
}
什麼是"永遠無法被執行到的程式碼"?
const foo = () => {
return 0;
console.log('aaa'); // 這一行程式碼就是永遠被執行到的程式碼
}
設定為undefined
時, 遇到這種情況會給出warning, 設定false則直接編譯時丟擲錯誤無法成功編譯, 設定為true既沒有警告也沒有錯誤
這個選項是針對標籤(label)語法的, 這個語法很罕見, 我也是看到了這個設定才知道有這個原來js還有Label
語法, label語法有點像其他語言裡的goto, 真是場景中幾乎不用
compilerOptions.allowUnusedLabels
表示是否允許未使用到的標籤
可選項:
undefined
: 這是預設值, 碰到未使用的標籤給出warning警告false
: 碰到未使用的標籤丟擲錯誤, 編譯失敗true
: 碰到未使用的標籤編譯通過, 且不給出異常function bar() {
console.log('loafing...');
loop: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 2) {
// break loop;
}
console.log(i, j, i + j);
}
}
}
預設值是true
, 開啟這個選項保證輸出的js程式碼處於ECMAScript標準的嚴格模式下, 也就是js檔案裡的use strict
這是typescript4.4中才加入的一個選項, 預設處於不開啟狀態; 開啟此選項, typescript會對可空屬性執行更嚴格的型別檢查, 可空屬性只有在初始化時可以留空為undefined
, 但是不能被手動設定為undefined
例如有一個IFoo
介面
interface IFoo {
foo?: string;
}
在compilerOptions.exactOptionalProperties = false
情況下
const obj: IFoo = {};
obj.foo = '1111';
console.log(obj.foo);
obj.foo = undefined;
console.log(obj.foo);
這段程式碼可以正常編譯通過
但如果開啟compilerOptions.exactOptionalProperties
選項後情況就不同了
const obj: IFoo = {};
obj.foo = '1111';
console.log(obj.foo);
// 編譯器會報: Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
obj.foo = undefined;
console.log(obj.foo);
// 這一行會報: Type '{ foo: undefined; }' is not assignable to type 'IFoo' with 'exactOptionalPropertyTypes: true'.
const obj2: IFoo = {
foo: undefined
}
先解釋下什麼是Downleveling
? Downleveling
是Typescript中的一個術語, 它表示將typescript程式碼轉譯為相對更低版本的javascript
這個標誌位元型樣是不開啟的.
開啟這個標誌位typescript會生成一個幫助方法來對es6中的for of
和陣列展開([...arr]
)語法進行轉譯, 以相容es3/es5
下面的範例用for of
迴圈並輸出一個包含符號表情的字串:
const text = `(