偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

為什么說(shuō)用 Babel 編譯 Typescript 是更好的選擇

開(kāi)發(fā) 前端
typescript 給 javascript 擴(kuò)展了類型的語(yǔ)法和語(yǔ)義,讓 js 代碼達(dá)到了靜態(tài)類型語(yǔ)言級(jí)別的類型安全,之前只能在運(yùn)行時(shí)發(fā)現(xiàn)的類型不安全的問(wèn)題,現(xiàn)在能在編譯期間發(fā)現(xiàn)了,所以大項(xiàng)目越來(lái)越多的選擇用 typescript 來(lái)寫(xiě)。

[[402840]]

本文轉(zhuǎn)載自微信公眾號(hào)「神光的編程秘籍」,作者神說(shuō)要有光。轉(zhuǎn)載本文請(qǐng)聯(lián)系神光的編程秘籍公眾號(hào)。

typescript 給 javascript 擴(kuò)展了類型的語(yǔ)法和語(yǔ)義,讓 js 代碼達(dá)到了靜態(tài)類型語(yǔ)言級(jí)別的類型安全,之前只能在運(yùn)行時(shí)發(fā)現(xiàn)的類型不安全的問(wèn)題,現(xiàn)在能在編譯期間發(fā)現(xiàn)了,所以大項(xiàng)目越來(lái)越多的選擇用 typescript 來(lái)寫(xiě)。除此之外,typescript 還能夠配合 ide 做更好的智能提示,這也是用 typescript 的一個(gè)理由。

類型安全:如果一個(gè)類型的變量賦值給它不兼容類型的值,這就是類型不安全,如果一個(gè)類型的對(duì)象,調(diào)用了它沒(méi)有的方法,這也是類型不安全。反之,就是類型安全。類型安全就是變量的賦值、對(duì)象的函數(shù)調(diào)用都是在類型支持的范圍內(nèi)。

最開(kāi)始 typescript 代碼只有自帶的 tyepscript compiler(tsc)能編譯,編譯不同版本的 typescript 代碼需要用不同版本的 tsc,通過(guò)配置 tsconfig.json 來(lái)指定如何編譯。

但是 tsc 編譯 ts 代碼為 js 是有問(wèn)題的:

tsc 不支持很多還在草案階段的語(yǔ)法,這些語(yǔ)法都是通過(guò) babel 插件來(lái)支持的,所以很多項(xiàng)目的工具鏈?zhǔn)怯?tsc 編譯一遍 ts 代碼,之后再由 babel 編譯一遍。這樣編譯鏈路長(zhǎng),而且生成的代碼也不夠精簡(jiǎn)。

所以,typescript 找 babel 團(tuán)隊(duì)合作,在 babel7 中支持了 typescript 的編譯,可以通過(guò)插件來(lái)指定 ts 語(yǔ)法的編譯。比如 api 中是這樣用:

  1. const parser = require('@babel/parser'); 
  2.  
  3. parser.parse(sourceCode, { 
  4.     plugins: ['typescript'
  5. }); 

這個(gè)插件是 typescript 團(tuán)隊(duì)與 babel 團(tuán)隊(duì)合作了一年的成果。

但是,這個(gè)插件真的能支持所有 typescript 代碼么?答案是否定的。

我們來(lái)看一下 babel 不支持哪些 ts 語(yǔ)法,為什么不支持。

babel 能編譯所有 typescript 代碼么?

babel 的編譯流程是這樣的:

  • parser: 把源碼 parse 成 ast
  • traverse:遍歷 ast,生成作用域信息和 path,調(diào)用各種插件來(lái)對(duì) ast 進(jìn)行轉(zhuǎn)換
  • generator:把轉(zhuǎn)換以后的 ast 打印成目標(biāo)代碼,并生成 sourcemap

而 typescript compiler 的編譯流程是這樣的:

  • scanner + parser:分詞和組裝 ast,從源碼到 ast 的過(guò)程
  • binder + checker:生成作用域信息,進(jìn)行類型推導(dǎo)和檢查
  • transform:對(duì)經(jīng)過(guò)類型檢查之后的 ast 進(jìn)行轉(zhuǎn)換

emitter:打印 ast 成目標(biāo)代碼,生成 sourcemap 和類型聲明文件(根據(jù)配置)

其實(shí) babel 的編譯階段和 tsc 的編譯階段是類似的,只是 tsc 多了一個(gè) checker,其余的部分沒(méi)什么區(qū)別。

  • babel 的 parser 對(duì)應(yīng) tsc 的 scanner + parser
  • babel 的 traverse 階段 對(duì)應(yīng) tsc 的 binder + transform
  • babel 的 generator 對(duì)應(yīng) tsc 的 emitter

那么能不能基于 babel 的插件在 traverse 的時(shí)候?qū)崿F(xiàn) checker 呢?

答案是不可以。

因?yàn)?tsc 的類型檢查是需要拿到整個(gè)工程的類型信息,需要做類型的引入、多個(gè)文件的 namespace、enum、interface 等的合并,而 babel 是單個(gè)文件編譯的,不會(huì)解析其他文件的信息。所以做不到和 tsc 一樣的類型檢查。

一個(gè)是在編譯過(guò)程中解析多個(gè)文件,一個(gè)是編譯過(guò)程只針對(duì)單個(gè)文件,流程上的不同,導(dǎo)致 babel 無(wú)法做 tsc 的類型檢查。

那么 babel 是怎么編譯 typescript 的呢?

其實(shí) babel 只是能夠 parse ts 代碼成 ast,不會(huì)做類型檢查,會(huì)直接把類型信息去掉,然后打印成目標(biāo)代碼。

這導(dǎo)致了有一些 ts 語(yǔ)法是 babel 所不支持的:

  • const enum 不支持。const enum 是在編譯期間把 enum 的引用替換成具體的值,需要解析類型信息,而 babel 并不會(huì)解析,所以不支持??梢杂孟鄳?yīng)的插件把 const enum 轉(zhuǎn)成 enum。
  • namespace 部分支持。不支持 namespace 的跨文件合并,不支持導(dǎo)出非 const 的值。這也是因?yàn)?babel 不會(huì)解析類型信息且是單文件編譯。

上面兩種兩個(gè)是因?yàn)榫幾g方式的不同導(dǎo)致的不支持。

  • export = import = 這種 ts 特有語(yǔ)法不支持,可以通過(guò)插件轉(zhuǎn)為 esm
  • 如果開(kāi)啟了 jsx 編譯,那么 aa 這種類型斷言不支持,通過(guò) aa as string 來(lái)替代。這是因?yàn)檫@兩種語(yǔ)法有沖突,在兩個(gè)語(yǔ)法插件(jsx、typescript)里,解決沖突的方式就是用 as 代替。

這四種就是 babel 不支持的 ts 語(yǔ)法,其實(shí)影響并不大,這幾個(gè)特性不用就好了。

結(jié)論:babel 不能編譯所有 typescript 代碼,但是除了 namespace 的兩個(gè)特性外,其余的都可以做編譯。

babel 是可以編譯 typescript 代碼,那么為什么要用 babel 編譯呢?

為什么要用 babel 編譯 typescript 代碼?

babel 編譯 typescript 代碼有 3 個(gè)主要的優(yōu)點(diǎn):

產(chǎn)物體積更小

tsc

tsc 如何配置編譯目標(biāo)呢?

在 compilerOptions 里面配置 target,target 設(shè)置目標(biāo)語(yǔ)言版本

  1.     compilerOptions: { 
  2.         target: "es5" // es3、es2015 
  3.     } 

typescript 如何引入 polyfill 呢?

在入口文件里面引入 core-js.

  1. import 'core-js'

babel7

babel7 是如何配置編譯目標(biāo)呢?

在 preset-env 里面指定 targets,直接指定目標(biāo)運(yùn)行環(huán)境(瀏覽器、node)版本,或者指定 query 字符串,由 browserslist 查出具體的版本。

  1.     presets: [ 
  2.         [ 
  3.             "@babel/preset-env"
  4.             { 
  5.                 targets: { 
  6.                     chrome: 45 
  7.                 } 
  8.             } 
  9.         ] 
  10.     ] 
  1.     presets: [ 
  2.         [ 
  3.             "@babel/preset-env"
  4.             { 
  5.                 targets: "last 1 version,> 1%,not dead" 
  6.             } 
  7.         ] 
  8.     ] 

babel7 如何引入 polyfill 呢?

也是在 @babel/preset-env 里面配置,除了指定 targets 之外,還要指定 polyfill 用哪個(gè)(corejs2 還是 corejs3),如何引入(entry 在入口引入 ,usage 每個(gè)模塊單獨(dú)引入用到的)。

  1.     presets: [ 
  2.         [ 
  3.             "@babel/preset-env"
  4.             { 
  5.                 targets: "last 1 version,> 1%,not dead"
  6.                 corejs: 3, 
  7.                 useBuiltIns: 'usage' 
  8.             } 
  9.         ] 
  10.     ] 

這樣可以根據(jù) @babel/compat-data 的數(shù)據(jù)來(lái)針對(duì)的做語(yǔ)法轉(zhuǎn)換和 api 的 polyfill:

先根據(jù) targets 查出支持的目標(biāo)環(huán)境的版本,再根據(jù)目標(biāo)環(huán)境的版本來(lái)從所有特性中過(guò)濾支持的,剩下的就是不支持的特性。只對(duì)這些特性做轉(zhuǎn)換和 polyfill 即可。

而且 babel 還可以通過(guò) @babel/plugin-transform-runtime 來(lái)把全局的 corejs 的 import 轉(zhuǎn)成模塊化引入的方式。

顯然,用 babel 編譯 typescript 從產(chǎn)物上看有兩個(gè)優(yōu)點(diǎn):

  • 能夠做更精準(zhǔn)的按需編譯和 polyfill,產(chǎn)物體積更小
  • 能夠通過(guò)插件來(lái)把 polyfill 變成模塊化的引入,不污染全局環(huán)境

從產(chǎn)物來(lái)看,babel 勝。

支持的語(yǔ)言特性

typescript 默認(rèn)支持很多 es 的特性,但是不支持還在草案階段的特性,babel 的 preset-env 支持所有標(biāo)準(zhǔn)特性,還可以通過(guò) proposal 來(lái)支持更多還未進(jìn)入標(biāo)準(zhǔn)的特性。

  1.     plugins: ['@babel/proposal-xxx'], 
  2.     presets: ['@babel/presets-env', {...}] 

從支持的語(yǔ)言特性來(lái)看,babel 勝。

編譯速度

tsc 會(huì)在編譯過(guò)程中進(jìn)行類型檢查,類型檢查需要綜合多個(gè)文件的類型信息,要對(duì) AST 做類型推導(dǎo),比較耗時(shí),而 babel 不做類型檢查,所以編譯速度會(huì)快很多。

從編譯速度來(lái)看, babel 勝。

總之,從編譯產(chǎn)物大小(主要)、支持的語(yǔ)言特性、編譯速度來(lái)看,babel 完勝。

但是,babel 不做類型檢查,那怎么類型檢查呢?

babel 和 tsc 的結(jié)合

babel 可以編譯生成更小的產(chǎn)物,有更快的編譯速度和更多的特性支持,所以我們選擇用 babel 編譯 typescript 代碼。但是類型檢查也是需要的,可以在 npm scripts 中配一個(gè)命令:

  1.     "scripts": { 
  2.         "typeCheck""tsc --noEmit" 
  3.     } 

這樣在需要進(jìn)行類型檢查的時(shí)候單獨(dú)執(zhí)行一下 npm run typeCheck 就行了,但最好在 git commit 的 hook 里(通過(guò) husky 配置)再執(zhí)行一次強(qiáng)制的類型檢查。

總結(jié)

typescript 給 js 擴(kuò)展了靜態(tài)類型的支持,使得代碼能夠在編譯期間檢查出賦值類型不匹配、調(diào)用了沒(méi)有的方法等錯(cuò)誤,保證類型安全。

除了 tsc 之外,babel7 也能編譯 typescript 代碼了,這是兩個(gè)團(tuán)隊(duì)合作一年的結(jié)果。

但是 babel 因?yàn)閱挝募幾g的特點(diǎn),做不了和 tsc 的多文件類型編譯一樣的效果,有幾個(gè)特性不支持(主要是 namespace 的跨文件合并、導(dǎo)出非 const 的值),不過(guò)影響不大,整體是可用的。

babel 做代碼編譯,還是需要用 tsc 來(lái)進(jìn)行類型檢查,單獨(dú)執(zhí)行 tsc --noEmit 即可。

 

babel 編譯 ts 代碼,相比 tsc 有很多優(yōu)點(diǎn):產(chǎn)物體積更小,支持更多特性,編譯速度更快。所以用 babel 編譯 typescript 是一個(gè)更好的選擇。

 

責(zé)任編輯:武曉燕 來(lái)源: 神光的編程秘籍
相關(guān)推薦

2022-03-14 08:33:09

TypeScriptJavaScript前端

2017-06-16 14:18:54

2020-07-03 14:05:26

Serverless云服務(wù)商

2021-11-29 18:27:12

Web Wasmjs

2011-09-20 15:51:42

NoSQL

2011-10-27 13:37:51

網(wǎng)頁(yè)設(shè)計(jì)

2023-05-05 16:26:33

2019-09-23 13:37:09

Anthos谷歌Kubernetes

2022-04-10 16:21:43

tscbabelTypeScrip

2019-09-23 13:10:02

容器進(jìn)程

2021-08-14 09:04:58

TypeScriptJavaScript開(kāi)發(fā)

2018-01-23 11:48:17

Vue.js前端開(kāi)發(fā)

2021-01-14 15:34:53

區(qū)塊鏈比特幣機(jī)器

2019-01-18 15:01:17

云計(jì)算運(yùn)維管理

2023-03-21 10:16:36

2023-05-04 07:44:13

編程界小語(yǔ)言Java

2021-02-25 14:09:55

人工智能數(shù)據(jù)機(jī)器學(xué)習(xí)

2022-07-27 16:50:39

BabelTypeScript前端

2014-08-18 10:58:20

編程語(yǔ)言編程書(shū)籍

2011-05-05 08:51:18

PHP
點(diǎn)贊
收藏

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