自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

會寫 TypeScript 但你真的會 TS 編譯配置嗎?

開發(fā) 前端
TypeScript 是一種基于 JavaScript 的強(qiáng)類型編程語言,它使得在前端項目開發(fā)過程中更加嚴(yán)謹(jǐn)且流暢,一定程度上保證了大型前端項目程序的健壯性。

最近遇到了挺多涉及到前端“編譯”方面的工作,其中關(guān)于 TypeScript 的編譯會涉及到關(guān)于 tsconfig.json 文件的配置,由于配置項繁雜,遂逐一解析并驗證,減少大家的一些疑惑,并提升工作效率!

隨著 TypeScript 的流行,越來越多的項目通過使用 TypeScript 來實現(xiàn)編寫代碼時候的類型提示和約束,從開發(fā)過程中減少 BUG 出現(xiàn)的概率,以此提升程序的健壯性和團(tuán)隊的研發(fā)效率。

為什么會單獨寫一篇文章來講述 tsconfig.json 文件的配置吶?原因是筆者在做 TS 項目的時候,由于對其中的配置項不熟悉,搞來搞去,搞好久,煩死了!所以決定好好梳理下。

越來越多的項目用上了 TypeScript,因此如何按需配置 tsconfig 也應(yīng)該是前端工程師需要掌握的技能之一。

本文內(nèi)容結(jié)構(gòu)如下,朋友們按需食用:

 

一、前置知識 

在熟悉掌握 tsconfig.json 文件配置前,先給首次接觸 TS 的同學(xué)預(yù)備一下“前置知識”。

1.1 TypeScript 是什么?

TypeScript 官網(wǎng):https://www.typescriptlang.org

TypeScript 是一種基于 JavaScript 的強(qiáng)類型編程語言,它使得在前端項目開發(fā)過程中更加嚴(yán)謹(jǐn)且流暢,一定程度上保證了大型前端項目程序的健壯性。

  • TypeScript 是由微軟開發(fā)的一款開源的編程語言;
  • TypeScript 是 JavaScript 的超集,遵循最新的 ESM 規(guī)范,TypeScript 擴(kuò)展了 JavaScript 的語法;
  • TypeScript 更像后端 JAVA、C# 這樣的面向?qū)ο笳Z言,可以讓 JS 開發(fā)大型企業(yè)級項目。

但是 TypeScript 并不可以直接運行,而是需要轉(zhuǎn)換成 JavaScript 代碼才可以在 Node.js 或瀏覽器環(huán)境下執(zhí)行,因此我們需要通過“編譯器”將 TS 代碼轉(zhuǎn)換為 JS 代碼。

1.2 什么是 tsc ?

tsc 的全稱是 TypeScript Compiler,也就是將 TypeScript 轉(zhuǎn)碼為 JavaScript 代碼的編譯器。

tsc 的全局安裝方式:

  1. npm install typescript -g 

當(dāng)我們編譯一份 index.ts 文件時,會使用下面的命令:

  1. tsc ./index.ts 

這樣就可以得到一份編譯成為 JavaScript 代碼的 ./index.js 文件。

tsc 實際就是將 TS 轉(zhuǎn)為 JS 的編譯(器)腳手架工具,如果是一個 TS 的前端工程項目,那么就可以通過項目中的 tsconfig.json 文件來自定義配置 TS 編譯相關(guān)規(guī)則。

項目中的 tsconfig.json 文件,我們一般會通過如下快捷命令生成:

  1. tsc --init 

執(zhí)行完后,會在項目根目錄生成一個簡單的初始化 tsconfig.json 配置描述文件,如果沒有特別的要求,該初始化配置就足以支持你愉快地使用 TS 開發(fā)啦!

更多相關(guān) TS 編譯配置和使用說明可以通過 tsc -h 查看。

1.3 tsconfig.json 文件

tsconfig.json[1] 文件是用于描述將 TypeScript 轉(zhuǎn)為 JavaScript 代碼的配置文件。

IDE(代碼編輯器)將會根據(jù) tsconfig.json 文件來對當(dāng)前項目中支持不同程度的類型約束,同時也是對 TSC 編譯 TypeScript 代碼過程做一些預(yù)定義、約束入口和編譯輸出目錄等配置。

因此對于一個支持 TypeScript 編程語言的工程來說,tsconfig.json 文件就是編碼的基礎(chǔ)。

二、tsconfig.json 配置詳解 

有了上面的前置知識作為基石,相信大家會對 tsconfig.json 文件的配置項也會更加容易理解。

  • tsconfig 的詳細(xì)配置:https://www.typescriptlang.org/tsconfig
  • tsconfig 的協(xié)議描述網(wǎng)址:http://json.schemastore.org/tsconfig

tsconfig 協(xié)議

 

筆者將從常見的配置項單獨解釋,然后在最后會將一些不常用的配置統(tǒng)一解釋,朋友們可以將這篇文章收藏一下,可當(dāng)作一份 tsconfig 配置的中文查詢對照表 👀。

2.1 files

files 字段用于指明需要 tsc 編譯的一個或多個 ts 文件,例如:

  1.   "files": ["index.ts""global.d.ts"], 

當(dāng)指定的文件或文件夾不存在時,會提示 ❌ 錯誤!

2.2 include

include 字段用于指明需要被 tsc 編譯的文件或文件夾列表,例如:

  1.   "include": [ 
  2.     "src"
  3.     "global.d.ts" 
  4.   ], 

2.3 exclude

exclude 字段用于排除不需要 tsc 編譯的文件或文件夾列表,例如:

  1.   "exclude": ["test.ts""src/test.ts"], 

注意: exclude 字段中的聲明只對 include 字段有排除效果,對 files 字段無影響,即與 include 字段中的值互斥。

如果 tsconfig.json 文件中 files 和 include 字段都不存在,則默認(rèn)包含 tsconfig.json 文件所在目錄及子目錄的所有文件,且排除在 exclude 字段中聲明的文件或文件夾。

2.4 compileOnSave

compileOnSave 是聲明是否需要在保存時候自動觸發(fā) tsc 編譯的字段,一般來說,我們的代碼編譯過程會通過 Rollup、Webpack 等打包構(gòu)建工具,并且使用熱更新,因此無需配置該項,保持缺省即可。

  1.   "compileOnSave"false

2.5 extendsextends

字段用于指明繼承已有的 tsconfig 配置規(guī)則文件。

該字段可以說是非常有用了,因為我們的 tsconfig 配置其實各個項目之間大同小異,因此完全可以結(jié)合自己團(tuán)隊的情況,抽離一個基礎(chǔ)且公共的 tsconfig 配置,并將其發(fā)包,然后作為 extends 字段的值來繼承配置。

tsconfig 推薦默認(rèn)配置可以參考官方的包:@tsconfig/recommended[2]

@tsconfig/recommended 的配置如下:

  1.   "compilerOptions": { 
  2.     "target""ES2015"
  3.     "module""commonjs"
  4.     "strict"true
  5.     "esModuleInterop"true
  6.     "skipLibCheck"true
  7.     "forceConsistentCasingInFileNames"true 
  8.   }, 
  9.   "$schema""https://json.schemastore.org/tsconfig"
  10.   "display""Recommended" 

例如繼承一個發(fā)包后的 tsconfig 基礎(chǔ)配置,并通過顯示聲明編譯的目標(biāo)代碼版本為 ES2016 來覆蓋覆蓋 @tsconfig/recommended 中對應(yīng)配置項。

  1.   "extends""@tsconfig/recommended/tsconfig.json"
  2.   "compilerOptions": { 
  3.     "target""ES2016" 
  4.   } 

作為一些實踐經(jīng)驗,社區(qū)也提供了一些常見環(huán)境(例如:Nuxt、Vite、Node 等)最佳實踐后的基礎(chǔ)配置,推薦參閱:https://github.com/tsconfig/bases/[3]

2.6 compilerOptions

compilerOptions 是一個描述 TypeScript 編譯器功能的“大”字段,其值類型是“對象”,因此包含了很多用于描述編譯器功能的子字段,其子字段的功能如下:

(1). target

target 字段指明經(jīng)過 TSC 編譯后的 ECMAScript 代碼語法版本,根據(jù) ECMAScript 語法標(biāo)準(zhǔn),默認(rèn)值為 ES3。

TypeScript 是 JavaScript 的超集,是對 JavaScript 語法和類型上的擴(kuò)展,因此我們可以使用 ES5、ES6,甚至是最新的 ESNext[4] 語法來編寫 TS。例如當(dāng)我們使用 ES2021 語法來編碼 TS 文件,同時配置如下:

  1.   "compilerOptions": { 
  2.     "target""ES5"
  3.   } 

則會將對應(yīng)使用了最新 ECMAScript 語法的 TS 文件編譯為符合 ES5 語法規(guī)范的 *.js 文件。

延伸一下知識點,思考一下 tsc 是如何將高版本(ECMAScript 規(guī)范)代碼向低版本代碼轉(zhuǎn)換的?這個轉(zhuǎn)換的結(jié)果靠譜嗎?與 Babel 有何差異?

一圖看 ECMAScript 各版本功能差異

另外對于個版本差異有想簡單了解的👬,可以閱讀《1.5萬字概括ES6全部特性[5]》

通過一個實驗,在 src/index.ts 文件中使用了 Map、Async/Await、Promise、擴(kuò)展運算符,并在 tsconfig.jon -> target 設(shè)置為 ES5:

驗證 target 降級處理

然后發(fā)現(xiàn)在右側(cè)的 dist/index.js 文件中,依然存在 new Map() 、Promise 語法,因此可以得出結(jié)論:tsc 的代碼降級編譯并不能完全處理兼容性。

通過官方文檔了解到:

這里提到了 lib 字段,意思是 target 不同的值會有對應(yīng)默認(rèn)的 lib 字段值,當(dāng)然也支持開發(fā)者顯示指明 lib 字段的值,那么接下來看看 lib 是干嘛的吧!

(2). lib

lib 字段是用于為了在我們的代碼中顯示的指明需要支持的 ECMAScript 語法或環(huán)境對應(yīng)的類型聲明文件。

例如我們的代碼會使用到瀏覽器中的一些對象 window、document,這些全局對象 API 對于 TypeScript Complier 來說是不能識別的:

lib 未顯示引入 DOM 會提示類型錯誤

因而需要在 lib 字段中如下配置:

  1.   "compilerOptions": { 
  2.     "target""ES5"
  3.     "lib": ["ES5""ES6""DOM"], 
  4.   } 

來顯式引入在 DOM 即瀏覽器環(huán)境下的一些默認(rèn)類型定義,即可在代碼中使用,window、document 等瀏覽器環(huán)境中的對象,TS 在運行時以及編譯時就不會報類型錯誤。

引入類型定義后無錯誤提示

綜合 target 和 lib 字段的實際功能表現(xiàn),我們可以得出結(jié)論:

TSC 的編譯結(jié)果只有部分特性做了 pollyfill 處理,ES6[6] 的一些特性仍然被保留,想要支持完全的降級到 ES5 還是需要額外引入 pollyfill(也就是我們在項目的入口文件處 import 'core-js'),但建議是將 target 字段值設(shè)置為 ES6,提升 TSC 的速度。

因此,筆者對于使用 TSC 編譯的觀點是:

不應(yīng)該將 TSC 作為編譯項目的工具,應(yīng)該將 TSC 作為類型檢查工具,代碼編譯的工作盡量交給 Rollup、Webpack 或 Babel 等打包工具!

另外推薦閱讀《為什么說用 babel 編譯 typescript 是更好的選擇》

(3). module

module 字段指明 tsc 編譯后的代碼應(yīng)該符合何種“模塊化方案”,可以指定的枚舉值有:none, commonjs, amd, system, umd, es2015, es2020, 或 ESNext,默認(rèn)值為 none。

在如今的前端開發(fā)趨勢來講,主要是使用 ESM、CommonJS、UMD、IIFE 四種模塊化方案,未來會趨向于 ESM,當(dāng)然我們會根據(jù)項目的應(yīng)用場景來決定使用何種模塊化方案,例如:NodeJS 使用 CommonJS,瀏覽器里可以使用 ESM,不過現(xiàn)在的打包工具,會自動處理 CommonJS 和 ESM 的差異,并包裝成符合指定模塊化規(guī)范的代碼,

在 tsconfig.json 可以設(shè)置 allowSyntheticDefaultImports 字段為 true,來允許合成默認(rèn)導(dǎo)入。

(4). esModuleInterop

簡單來說,就是支持合成默認(rèn)導(dǎo)入。

在前端項目開發(fā)時,使用 ESM 編寫代碼引入了 CJS 的模塊,由于 CJS 模塊沒有默認(rèn)導(dǎo)出內(nèi)容,因此需要通過我們的工具去自動化合成 CJS 的默認(rèn)導(dǎo)出,以支持在 ESM 下流暢開發(fā)。

參閱文章《esModuleInterop 到底做了什么?[7]》,講得非常詳細(xì)也非常好。

當(dāng) esModuleInterop 字段設(shè)置為 true 時候,上述提到的 allowSyntheticDefaultImports 字段也會自動設(shè)置為 true。

(5). moduleResolution

moduleResolution 聲明如何處理模塊,枚舉值:classic、node,會根據(jù) module 字段決定默認(rèn)值。

推薦手動設(shè)置為 node,更符合現(xiàn)在大家的編碼認(rèn)識一些,而且大部分的構(gòu)建打包工具都是基于 Node。

舉個,遇到 import {a} from 'a-lib'; 這樣的模塊引入代碼應(yīng)該如何去(解析)查找到對應(yīng)的模塊文件。

(6). baseUrl & paths

baseUrl:設(shè)置基本目錄以解析非絕對模塊名稱(定義一個根目錄,以此進(jìn)行絕對文件路徑解析)

paths:用于設(shè)置模塊名或路徑映射列表,這樣就可以簡寫項目中自定義模塊的文件路徑。

舉一個 :

  1.   "compilerOptions": { 
  2.     // 注意:baseUrl 必選,與 paths 成對出現(xiàn),以 tsconfig.json 文件所在目錄開始 
  3.     "baseUrl"".",  
  4.     "paths": { 
  5.       // 映射列表 
  6.       "@/*": [ 
  7.         "src/*" 
  8.       ], 
  9.       "moduleA": [ 
  10.         "src/libs/moduleA" 
  11.       ] 
  12.     } 
  13.   } 
  14.  
  15. // 代碼里這么寫 
  16. import Toast from '@/components/Toast.ts' // 模塊實際位置: src/components/Toast.ts 
  17. import TestModule from 'moduleA/index.js' // 模塊實際位置: src/libs/moduleA/index.js 

⚠️ 注意: 如果需要自動生成(導(dǎo)出)類型定義文件,TSC 不會處理路徑別名,需要引入 typescript-transform-paths[8] 插件,以及 TTypescript[9] 來轉(zhuǎn)換路徑別名為相對路徑。

由于當(dāng)前的 TypeScript 不支持 tsconfig.json 中的自定義轉(zhuǎn)換器,且無法使用 tsc 命令使用自定義轉(zhuǎn)換器編譯文件,所以引入了 TTypescript 作為包裝器

  1. // tsconfig.json 
  2.   "compilerOptions": { 
  3.     "baseUrl""./"
  4.     // 配置路徑別名映射 
  5.     "paths": { 
  6.       "@/*": ["src/*"
  7.     }, 
  8.     "plugins": [ 
  9.       // 轉(zhuǎn)換輸出 js 文件中的路徑 
  10.       { "transform""typescript-transform-paths" }, 
  11.  
  12.       // 轉(zhuǎn)換輸出 .d.ts 文件中的路徑 
  13.       { "transform""typescript-transform-paths""afterDeclarations"true } 
  14.     ] 
  15.   } 

plugins[10] 是用于擴(kuò)展 TSC 編譯器功能的字段。

例如在 Rollup 打包環(huán)境下,可以如下配置:

  1. import typescript from '@rollup/plugin-typescript'
  2. import ttypescript from 'ttypescript'
  3.  
  4. export default [ 
  5.   { 
  6.     input: './src/index.ts'
  7.     output: { 
  8.       dir: 'dist'
  9.       format: 'cjs'
  10.       entryFileNames: 'index.js'
  11.     }, 
  12.     plugins: [ 
  13.       typescript({ 
  14.         typescript: ttypescript, 
  15.       }), 
  16.     ], 
  17.   }, 
  18. ]; 

如果是有自動導(dǎo)出類型定義文件的需求,才需要搞這一套插件~

(7). rootDir & outDir

rootDir:指定 TypeScript 識別讀取的根目錄,用于所有非聲明輸入文件的最長公共路徑

例如:'"rootDir": "./src",則 src 目錄下的 TS 文件不能引用 src 目錄以外的 ts 文件,一般我們會設(shè)置為 ./src 或 ./(即 tsconfig.json 所在目錄)

outDir:輸出目錄,即 tsc 編譯后的文件輸出的文件夾路徑(基于 tsconfig.json 文件的相對路徑)

例如:"outDir": "./dist",及將 TSC 編譯輸出的 JS 文件,統(tǒng)一輸出的 ./dist 目錄下。

(8). jsx

如果是有 jsx 語法需要支持的項目,可以設(shè)置值 preserve、react 等

  1.   "compilerOptions": { 
  2.     "jsx""preserve", // 一般 preserve 即可 
  3.   }, 

(9). importHelpers

importHelpers 決定是否啟用從 tslib 庫引入語法降級輔助函數(shù),以避免重復(fù)冗余的輔助函數(shù)聲明。

個人建議是設(shè)置為 true 來啟用。

(10).experimentalDecorators

experimentalDecorators 用于聲明是否啟實驗性用裝飾器模式。

TypeScript 和 ES6 中引入了 Class 的概念,同時在 Decorators[11] 提出了裝飾器模式,通過引入裝飾器模式,能極大簡化書寫代碼。

當(dāng)前對于 Decorator 的支持性不太好,如果是一些涉及到使用了裝飾器的需要,就需要開啟這個屬性。

(11). noEmit

noEmit 設(shè)置是否輸出 js 文件,一般是設(shè)置為 false,將打包等工作交給 Webpack 等工具。

三、tsconfig.json 全解析 

上面針對 tsconfig.json 中一些常見配置做了詳細(xì)解釋,將一些不常用的配置字段組合在一起,做一個 Checklist 如下:

  1.   "compilerOptions": { 
  2.     /* 基本選項 */ 
  3.     "target""es6", // 指定 ECMAScript 目標(biāo)版本: 'ES3' (default), 'ES5''ES2015''ES2016''ES2017'or 'ESNEXT' 
  4.     "module""commonjs", // 指定使用模塊: 'commonjs''amd''system''umd' or 'es2015' 
  5.     "lib": [], // 指定要包含在編譯中的庫文件 
  6.     "allowJs"true, // 允許編譯 javascript 文件 
  7.     "checkJs"true, // 報告 javascript 文件中的錯誤 
  8.     "jsx""preserve", // 指定 jsx 代碼的生成: 'preserve''react-native'or 'react' 
  9.     "declaration"true, // 生成相應(yīng)的 '.d.ts' 文件 
  10.     "declarationDir""./dist/types", // 生成的 '.d.ts' 文件保存文件夾 
  11.     "sourceMap"true, // 生成相應(yīng)的 '.map' 文件 
  12.     "outFile""./", // 將輸出文件合并為一個文件 
  13.     "outDir""./dist", // 指定輸出目錄 
  14.     "rootDir""./", // 用來控制輸出目錄結(jié)構(gòu) --outDir. 
  15.     "removeComments"true, // 刪除編譯后的所有的注釋 
  16.     "noEmit"true, // 不生成輸出文件 
  17.     "importHelpers"true, // 從 tslib 導(dǎo)入輔助工具函數(shù) 
  18.     "isolatedModules"true, // 將每個文件做為單獨的模塊 (與 'ts.transpileModule' 類似). 
  19.  
  20.     /* 嚴(yán)格的類型檢查選項 */ 
  21.     "strict"true, // 啟用所有嚴(yán)格類型檢查選項 
  22.     "noImplicitAny"true, // 在表達(dá)式和聲明上有隱含的 any類型時報錯 
  23.     "strictNullChecks"true, // 啟用嚴(yán)格的 null 檢查 
  24.     "noImplicitThis"true, // 當(dāng) this 表達(dá)式值為 any 類型的時候,生成一個錯誤 
  25.     "alwaysStrict"true, // 以嚴(yán)格模式檢查每個模塊,并在每個文件里加入 'use strict' 
  26.  
  27.     /* 額外的檢查 */ 
  28.     "noUnusedLocals"true, // 有未使用的變量時,拋出錯誤 
  29.     "noUnusedParameters"true, // 有未使用的參數(shù)時,拋出錯誤 
  30.     "noImplicitReturns"true, // 并不是所有函數(shù)里的代碼都有返回值時,拋出錯誤 
  31.     "noFallthroughCasesInSwitch"true, // 報告switch語句的fallthrough錯誤。(即,不允許switch的case語句貫穿) 
  32.  
  33.     /* 模塊解析選項 */ 
  34.     "moduleResolution""node", // 選擇模塊解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6) 
  35.     "baseUrl""./", // 用于解析非相對模塊名稱的基礎(chǔ)目錄 
  36.     "paths": {}, // 模塊名到基于 baseUrl 的路徑映射的列表 
  37.     "rootDirs": [], // 根文件夾列表,其組合內(nèi)容表示項目運行時的結(jié)構(gòu)內(nèi)容 
  38.     "typeRoots": [], // 包含類型聲明的文件列表 
  39.     "types": [], // 需要包含的類型聲明文件名列表 
  40.     "allowSyntheticDefaultImports"true, // 允許從沒有設(shè)置默認(rèn)導(dǎo)出的模塊中默認(rèn)導(dǎo)入。 
  41.     "esModuleInterop"true, // 支持合成模塊的默認(rèn)導(dǎo)入 
  42.    
  43.     /* Source Map Options */ 
  44.     "sourceRoot""./", // 指定調(diào)試器應(yīng)該找到 TypeScript 文件而不是源文件的位置 
  45.     "mapRoot""./", // 指定調(diào)試器應(yīng)該找到映射文件而不是生成文件的位置 
  46.     "inlineSourceMap"true, // 生成單個 soucemaps 文件,而不是將 sourcemaps 生成不同的文件 
  47.     "inlineSources"true, // 將代碼與 sourcemaps 生成到一個文件中,要求同時設(shè)置了 --inlineSourceMap 或 --sourceMap 屬性 
  48.  
  49.     /* 其他選項 */ 
  50.     "experimentalDecorators"true, // 啟用裝飾器 
  51.     "emitDecoratorMetadata"true // 為裝飾器提供元數(shù)據(jù)的支持 
  52.   }, 
  53.   /* 指定編譯文件或排除指定編譯文件 */ 
  54.   "include": ["src/**/*"], 
  55.   "exclude": ["node_modules""**/*.spec.ts"], 
  56.   "files": ["index.ts""test.ts"], 
  57.   // 從另一個配置文件里繼承配置 
  58.   "extends""@tsconfig/recommended"
  59.   // 讓 IDE 在保存文件的時候根據(jù) tsconfig.json 重新生成文件 
  60.   "compileOnSave"true // 支持這個特性需要Visual Studio 2015, TypeScript 1.8.4 以上并且安裝 atom-typescript 插件 

四、打包工具中的 TypeScript 

前文講到了為什么不推薦直接使用 TSC 作為項目的打包編譯工具,那么接下來就簡單看看在常見的幾款打包工具中針對 TypeScript 的編譯方案是如何設(shè)計的?

4.1 Rollup + TypeScript

在 Rollup 打包中,我們一般只需要添加 @rollup/plugin-typescript[12] 插件即可,該插件會默認(rèn)讀取項目根目錄下的 tsconfig.json 配置文件。

Rollup 的配置就像這樣:

  1. // file: rollup.config.js 
  2. import typescript from '@rollup/plugin-typescript'
  3.  
  4. export default { 
  5.   input: 'src/index.ts'
  6.   output: { 
  7.     dir: 'output'
  8.     format: 'cjs' 
  9.   }, 
  10.   plugins: [typescript()] 
  11. }; 

結(jié)合其源碼:

默認(rèn)使用 TSC 作為 TS 的編譯器

因為 typescript 聲明了是 peerDependencies,因此會采用項目中安裝的 typescript 版本,即是使用我們項目中的 TS 編譯器。

通過閱讀 @rollup/plugin-typescript 源碼,可以看到該插件會默認(rèn)使我們自己項目中的 tsconfig.json 文件作為 TSC 編譯的配置,但會做一些配置預(yù)設(shè)覆蓋:

會調(diào)用 ts.parseJsonConfigFileContent() 方法,將 FORCED_COMPILER_OPTIONS 值 merge 到用戶的自定義配置中。

FORCED_COMPILER_OPTIONS

通過英文解釋看到,因為需要 TSC 編譯獲得 JS 產(chǎn)物,所以會將 noEmit 設(shè)置為 false,也就是 TSC 編譯會輸出文件,但為什么我們在輸出目錄卻沒有看到對應(yīng)的 TSC 產(chǎn)物吶?

TSC 編譯結(jié)果存儲到內(nèi)存中

但是如果開啟了 declaration,則會將 TSC 解析得到的 *.d.ts 文件輸出到指定目錄。

4.2 Webpack + TypeScript

在 Webpack 中的 TypeScript[13] 官方文檔中,指明了需要安裝:typescript 和 ts-loader 兩個模塊。

配置 Webpack 并支持 TypeScript 的配置如下:

  1. // file: webpack.config.js 
  2. const path = require('path'); 
  3.  
  4. module.exports = { 
  5.   entry: './src/index.ts'
  6.   module: { 
  7.     rules: [ 
  8.       { 
  9.         test: /\.tsx?$/, 
  10.         use: 'ts-loader'
  11.         exclude: /node_modules/, 
  12.       }, 
  13.     ], 
  14.   }, 
  15.   resolve: { 
  16.     extensions: ['.tsx''.ts''.js'], 
  17.   }, 
  18.   output: { 
  19.     filename: 'bundle.js'
  20.     path: path.resolve(__dirname, 'dist'), 
  21.   }, 
  22. }; 

可以看出 Webpack 主要是依賴 ts-loader 實現(xiàn)對 TypeScript 語法的編譯支持,再看看對 ts-loader 的介紹:

ts-loader

換句話說,ts-loader 實際調(diào)用了 TSC 來編譯 TS 文件,TSC 的配置依賴于你項目中的 tsconfig.json 文件。

如果使用了 Babel,則可以使用 @babel/preset-typescript[14] 來處理,但 Babel 不會做 TS 類型校驗,在打包工具 Rollup 和 Webpack 中都可以引入 Babel,那么接下來看看 Babel 是如何處理 TypeScript 的吧!

4.3 Babel + TypeScript

Babel 處理 TS 需要安裝 @babel/preset-typescript 模塊,然后在 babel 項目配置文件中聲明:

  1. // 配置說明:https://babeljs.io/docs/en/babel-preset-typescript 
  2.   "presets": ["@babel/preset-typescript"

但 Babel 中只會對 TS 代碼轉(zhuǎn)為 JS 代碼(通過 parse TS 文件為 AST,并直接移除類型信息,然后打印目標(biāo)代碼),不會去做 TS 類型檢查,所以 Babel 編譯 TS 文件相較于 TSC 的速度更快!

同時,因為 Babel 會根據(jù)不同的兼容環(huán)境,按需引入 pollyfill,比 TSC 直接引入 core-js 更優(yōu)雅,因此使用了 Babel 打包的體積也會更小。

TS 類型檢查工作可以交給代碼編輯器承擔(dān),當(dāng)然同時可以新增 TS 檢查的命令:

  1. // package.json 
  2.   "script": { 
  3.     "tsCheck""tsc --noEmit"
  4.   } 

可以把類型檢查放到特定的 npm scripts 生命周期之前,另外其實也可以將類型檢查放到 git commit 階段,用于做必要的 TS 類型檢查,保證項目的正確性。

4.4 ESbuild + TypeScript

通過 Vite 體會到了 ESbuild[15] 帶來的開發(fā)熱更新“極速”體驗,針對 TS 項目,ESbuild 和 Babel 是相同的編譯策略,即僅編譯,不校驗類型。

ESbuild 處理 TypeScript[16] 同樣可以帶來飛一般的感覺!

Vite 使用 esbuild 將 TypeScript 轉(zhuǎn)譯到 JavaScript,約是 tsc 速度的 20~30 倍,同時 HMR 更新反映到瀏覽器的時間小于 50ms。—— Vite Docs[17]

但在 ESbuild 中需要啟用 tsconfig 中的 isolatedModules 功能,然后在類型引入的時候需要替換,規(guī)則參考如下:

  1. // old 
  2. import { UserType } from './types'
  3.  
  4. // new 
  5. import type { UserType } from './types'

因為 ESbuild 是單獨編譯每個文件,無法判斷引入的是 Type(類型) 還是 值,所以需要開發(fā)者顯示地聲明是“Type”。

同時還需要啟用 esModuleInterop 功能,用于支持 ESM 模塊合成默認(rèn)導(dǎo)入,以兼容 CJS 和 ESM 規(guī)范。

另外 ESbuild 不支持:emitDecoratorMetadat、const enum 類型和 *.d.ts 文件

此外,關(guān)注到兼容性處理這方面,Bable 和 ESbuild 是類似的,因此會存在兼容性問題:

兼容性

對于裝飾器處理不支持,因為 TS 是 JS 的超集,ESnext 的規(guī)范提案某些還不是穩(wěn)定的,因此如果有這方面訴求的項目,可以借助 TSC 做預(yù)編譯,例如使用 Rollup 的 typescript 插件 或 Webpack 的 ts-loader 方式。

五、總結(jié) 

針對 TypeScript 項目的類型檢查和編譯流程算是完整過了一遍,相信已足以支撐大家在工作中自定義化配置 TS 前端項目!

另外,tsconfig.json 推薦配置策略如下:

  1. 借助 extends 字段,并結(jié)合項目應(yīng)用場景,繼承官方推薦配置
  2. 針對項目特點,按需修改對應(yīng)功能配置
  3. 建議啟用 importHelpers、esModuleInterop,取消 noEmit 輸出
  4. TS 項目的打包構(gòu)建,推薦使用 Webpack、Rollup、Bable 等專業(yè)工具來保證正確性和構(gòu)建優(yōu)化

參考資料

[1]TSconfig.json 手冊: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html

[2]@tsconfig/recommended: https://www.npmjs.com/package/@tsconfig/recommended

[3]TSconfig 最佳實踐配置: https://github.com/tsconfig/bases/

[4]ES.Next 語法提案: https://github.com/tc39/proposals

[5]1.5萬字概括ES6全部特性: https://watesegmentfault.com/a/1190000020678240

[6]ES6 語法新特性: http://es6-features.org/#Constants

[7]esModuleInterop 到底做了什么?: https://zhuanlan.zhihu.com/p/148081795

[8]typescript-transform-paths: https://www.npmjs.com/package/typescript-transform-paths

[9]TTypescript: https://www.npmjs.com/package/ttypescript

[10]compilerOptions.plugins: https://www.typescriptlang.org/tsconfig#plugins

[11]Decorators: https://github.com/tc39/proposal-decorators

[12]@rollup/plugin-typescript: https://github.com/rollup/plugins/tree/master/packages/typescript/#readme

[13]Webpack 中的 TypeScript: https://webpack.docschina.org/guides/typescript/

[14]@babel/preset-typescript: https://babeljs.io/docs/en/babel-preset-typescript

[15]ESbuild: https://esbuild.github.io/

[16]ESbuild 處理 TypeScript: https://esbuild.github.io/content-types/#typescript

[17]Vite Docs: https://cn.vitejs.dev/guide/features.html#typescript

 

責(zé)任編輯:姜華 來源: DYBOY
相關(guān)推薦

2019-08-27 08:24:17

簡歷技能工作

2019-12-27 08:33:45

Java工具IDE

2022-03-25 09:39:50

LinuxLinux top

2017-11-07 12:35:53

比特幣區(qū)塊鏈虛擬貨幣

2022-04-07 16:03:36

JavaScriptTypeScript

2021-07-13 06:42:58

JavaEquals方法

2017-11-13 14:06:56

2019-01-22 15:37:01

GitHub代碼開發(fā)者

2023-03-01 09:39:05

2016-06-01 15:42:58

Hadoop數(shù)據(jù)管理分布式

2020-04-17 14:25:22

Kubernetes應(yīng)用程序軟件開發(fā)

2022-07-26 00:00:22

HTAP系統(tǒng)數(shù)據(jù)庫

2014-04-17 16:42:03

DevOps

2017-10-10 11:11:14

2024-04-23 08:31:57

pythonfalse

2019-05-13 14:20:19

正則表達(dá)式JavaScript前端

2022-05-09 14:09:23

多線程線程安全

2021-04-23 07:27:31

內(nèi)存分配CPU

2021-01-15 07:44:21

SQL注入攻擊黑客

2022-08-15 10:42:50

千兆網(wǎng)絡(luò)千兆光纖
點贊
收藏

51CTO技術(shù)棧公眾號