Typescript體系

TS是什么

為什么要用TS

TS能干什么

社區(qū)發(fā)展

周邊生態(tài)

深入理解TS

接受TS

權(quán)衡

TS是什么

Typescript=Type + script(標(biāo)準(zhǔn)js), 我們從TS的官方網(wǎng)站上就能看到定義:TypeScript is a typed superset of JavaScript that compiles to plain JavaScript。TypeScript是一個(gè)編譯到純JS的有類型定義的JS超集。?

為什么要用TS

目標(biāo):生命周期較長(常常持續(xù)幾年)的復(fù)雜SPA應(yīng)用,保障開發(fā)效率的同時(shí)提升代碼的可維護(hù)性和線上運(yùn)行時(shí)質(zhì)量。

從開發(fā)效率上看,雖然需要多寫一些類型定義代碼,但TS在VSCode、WebStorm等IDE下可以做到智能提示,智能感知bug,同時(shí)我們項(xiàng)目常用的一些第三方類庫框架都有TS類型聲明,我們也可以給那些沒有TS類型聲明的穩(wěn)定模塊寫聲明文件,如我們的前端KOP框架(目前還是螞蟻內(nèi)部框架,類比dva),這在團(tuán)隊(duì)協(xié)作項(xiàng)目中可以提升整體的開發(fā)效率。

從可維護(hù)性上看,長期迭代維護(hù)的項(xiàng)目開發(fā)和維護(hù)的成員會(huì)有很多,團(tuán)隊(duì)成員水平會(huì)有差異,而軟件具有的特質(zhì),長期迭代維護(hù)的項(xiàng)目總會(huì)遇到可維護(hù)性逐漸降低的問題,有了強(qiáng)類型約束和靜態(tài)檢查,以及智能IDE的幫助下,可以降低軟件腐化的速度,提升可維護(hù)性,且在重構(gòu)時(shí),強(qiáng)類型和靜態(tài)類型檢查會(huì)幫上大忙,甚至有了類型定義,會(huì)不經(jīng)意間增加重構(gòu)的頻率(更安全、放心)。

從線上運(yùn)行時(shí)質(zhì)量上看,我們現(xiàn)在的SPA項(xiàng)目的很多bug都是由于一些調(diào)用方和被調(diào)用方(如組件模塊間的協(xié)作、接口或函數(shù)的調(diào)用)的數(shù)據(jù)格式不匹配引起的,由于TS有編譯期的靜態(tài)檢查,讓我們的bug盡可能消滅在編譯器,加上IDE有智能糾錯(cuò),編碼時(shí)就能提前感知bug的存在,我們的線上運(yùn)行時(shí)質(zhì)量會(huì)更為穩(wěn)定可控。

一個(gè)復(fù)雜軟件的常規(guī)研發(fā)流程,大致分為定義問題、需求分析、規(guī)劃構(gòu)建、軟件架構(gòu)、詳細(xì)設(shè)計(jì)、編碼調(diào)試、單元測試、集成測試、集成、系統(tǒng)測試、保障維護(hù)。構(gòu)建活動(dòng)(主要是編碼調(diào)試)在中大型項(xiàng)目中的工作量占比大于50%。同時(shí),一個(gè)中大型項(xiàng)目,bug由構(gòu)建階段引起的比例占到50%~75%,對于一個(gè)成功的項(xiàng)目來說,構(gòu)建活動(dòng)是必須要做的,而且是工程師更為可控的?!敬a大全】

TS適合大規(guī)模JavaScript應(yīng)用,正如他的官方宣傳語JavaScript that scales。從以下幾點(diǎn)可以看到TS在團(tuán)隊(duì)協(xié)作、可維護(hù)性、易讀性、穩(wěn)定性(編譯期提前暴露bug)等方面上有著明顯的好處:

加上了類型系統(tǒng),對于閱讀代碼的人和編譯器都是友好的。對閱讀者來說,類型定義加上IDE的智能提示,增強(qiáng)了代碼的易讀型;對于編譯器來說,類型定義可以讓編譯器揪出隱藏的bug。

類型系統(tǒng)+靜態(tài)分析檢查+智能感知/提示,使大規(guī)模的應(yīng)用代碼質(zhì)量更高,運(yùn)行時(shí)bug更少,更方便維護(hù)。

有類似VSCode這樣配套的IDE支持,方便的查看類型推斷和引用關(guān)系,可以更方便和安全的進(jìn)行重構(gòu),再也不用全局搜索,一個(gè)個(gè)修改了。

給應(yīng)用配置、應(yīng)用狀態(tài)、前后端接口及各種模塊定義類型,整個(gè)應(yīng)用都是一個(gè)個(gè)的類型定義,使協(xié)作更為方便、高效和安全。

TS能干點(diǎn)什么

靜態(tài)檢查

這類問題是ESLint等工具檢測不出來的。

低級錯(cuò)誤

constpeoples = [{? name:'tim',? age:20}, {? name:'alex',? age:22}];constsortedPeoples = peoples.sort((a, b) =>a.name.localCompare(b.name));復(fù)制代碼

執(zhí)行TS編譯命令tsc,檢測到錯(cuò)誤:

error TS2339: Property'localCompare'does not exist ontype'string'.復(fù)制代碼

如果是在支持TS的IDE中(VS Code、WebStorm等),則不需等到編譯,在IDE中就可以非常明顯在localCompare位置提示出錯(cuò)誤信息。

localCompare這種輸入手誤(或者手滑不小心刪除或添加了字符)時(shí)有發(fā)生,如果沒有編譯器靜態(tài)檢查,那有可能就是一個(gè)字符引發(fā)的血案:埋下了一個(gè)隱藏的運(yùn)行時(shí)bug。如果在SPA應(yīng)用中,這個(gè)問題需要較長的操作路徑才能被發(fā)現(xiàn),一旦用戶觸發(fā)這個(gè)地雷,那它就會(huì)爆炸:應(yīng)用直接crash(在沒有頁面刷新的SPA中問題尤為凸顯)。

非空判斷

letdata = {? list:null,? success:true};constvalue = data.list.length;復(fù)制代碼

執(zhí)行tsc編譯:

error TS2532: Object is possibly'null'.復(fù)制代碼

data.list.length這行直接引用了data.list的屬性,但data.list的數(shù)據(jù)格式有不是數(shù)組的可能性,這種場景在前端處理后端接口返回時(shí)經(jīng)常出現(xiàn),接口返回的數(shù)據(jù)層級可能非常深,如果在某一級缺少了非空判斷邏輯,那就意味著埋下了一個(gè)不知道什么時(shí)候就會(huì)引爆的炸彈。

類型推斷

constarr = [];arr.toUpperCase();classCat{? miao() {}}classDog{? wang() {}}constcat =newCat();cat.wang();復(fù)制代碼

執(zhí)行tsc編譯:

error TS2339: Property'toUpperCase'does not exist ontype'any[]'.error TS2339: Property'wang'does not exist ontype'Cat'.復(fù)制代碼

TS有類型推斷,給不同類型的執(zhí)行對象調(diào)用錯(cuò)誤的方法都將被檢查出來。

面向?qū)ο缶幊淘鰪?qiáng)

訪問權(quán)限控制

classPerson {protectedname:string;publicage:number;constructor(name:string) {this.name = name; }}classEmployeeextendsPerson {staticsomeAttr =1;privatedepartment:string;constructor(name:string, department:string) {super(name);this.department = department;? }}lethoward =newEmployee("Howard","Sales");console.log(howard.name);復(fù)制代碼

執(zhí)行tsc編譯:

error TS2445: Property'name'is protected and only accessible within class'Person'and its subclasses.復(fù)制代碼

Person中name屬性是protected類型,只能在自己類中或者子類中使用。訪問權(quán)限控制在面向?qū)ο缶幊讨泻苡杏?,他能幫忙我們做到信息隱藏,JS面向?qū)ο缶幊痰囊粋€(gè)大問題就是沒有提供原生支持信息隱藏的方案(很多時(shí)候都是通過約定編碼方式來做)。信息隱藏有助于更好的管理系統(tǒng)的復(fù)雜度,這在軟件工程中顯得尤為重要。

接口

interfaceMachine {? move():void}interfaceHuman {? run():void}classBase {}classRobotextendsBaseimplementsMachine, Human {? run() {console.log('run');? }? move() {console.log('move');? }}復(fù)制代碼

Robot類可以繼承Base類,并實(shí)現(xiàn)Machine和Human接口,這種可以組合繼承類和實(shí)現(xiàn)接口的方式使面向?qū)ο缶幊谈鼮殪`活、可擴(kuò)展性更好。

泛型

classGenericNumber {? ? zeroValue: T;? ? add:(x: T, y: T) =>T;}letmyGenericNumber =newGenericNumber();myGenericNumber.zeroValue =0;myGenericNumber.add =function(x, y){returnx + y; };復(fù)制代碼

定義了一個(gè)模板類型T,實(shí)例化GenericNumber類時(shí)可以傳入內(nèi)置類型或者自定義類型。泛型(模板)在傳統(tǒng)面向?qū)ο缶幊陶Z言中是很常見的概念了,在代碼邏輯是通用模式化的,參數(shù)可以是動(dòng)態(tài)類型的場景下比較有用。

類型系統(tǒng)

interfaceSystemConfig {? attr1:number;? attr2:string;? func1():string;}interfaceModuleType {? data: {? ? attr1?:string,? ? attr2?:number},? visible:boolean}constconfig: SystemConfig = {? attr1:1,? attr2:'str',? func1:()=>''};constmod: ModuleType = {? data: {? ? attr1:'1'},? visible:true};復(fù)制代碼

我們定義了一個(gè)系統(tǒng)配置類型SystemConfig和一個(gè)模塊類型ModuleType,我們在使用這些類型時(shí)就不能隨便修改config和mod的數(shù)據(jù)了。每個(gè)被調(diào)用方負(fù)責(zé)自己的對外類型展現(xiàn),調(diào)用者只需關(guān)心被調(diào)用方的類型,不需關(guān)心內(nèi)部細(xì)節(jié),這就是類型約束的好處,這對于多人協(xié)作的團(tuán)隊(duì)項(xiàng)目非常有幫助。

模塊系統(tǒng)增強(qiáng)

namespaceN {exportnamespaceNN {exportfunctiona(){console.log('N.a');? ? }? }}N.NN.a();復(fù)制代碼

TS除了支持ES6的模塊系統(tǒng)之外,還支持命名空間。這在管理復(fù)雜模塊的內(nèi)部時(shí)比較有用。

使用TS的成本

學(xué)習(xí)成本

理論上學(xué)習(xí)并應(yīng)用一門新語言是需要很高成本的,但好在TS本身是JS的超集,這也意味著他本身是可以支持現(xiàn)有JS代碼的,至少理論上是這樣。學(xué)習(xí)一下類型系統(tǒng)的相關(guān)知識和面向?qū)ο蟮幕A(chǔ)知識,應(yīng)該可以hold住TS,成本不會(huì)很高。官方文檔是最好的學(xué)習(xí)材料。

應(yīng)用成本

老項(xiàng)目

對于老項(xiàng)目,由于TS兼容ES規(guī)范,所以可以比較方便的升級現(xiàn)有的JS(這里指ES6及以上)代碼,逐漸的加類型注解,漸進(jìn)式增強(qiáng)代碼健壯性。遷移過程:

npm全局安裝typescript包,并在工程根目錄運(yùn)行tsc --init,自動(dòng)產(chǎn)生tsconfig.json文件。默認(rèn)的3個(gè)配置項(xiàng):更多配置項(xiàng)說明

"target":"es5": 編譯后代碼的ES版本,還有es3,es2105等選項(xiàng)。

"module":"commonjs":編譯后代碼的模塊化組織方式,還有amd,umd,es2015等選項(xiàng)。

"strict":true:嚴(yán)格校驗(yàn),包含不能有沒意義的any,null校驗(yàn)等選項(xiàng)。

初始化得到的tsconfig.json無需修改,增加"allowJs": true選項(xiàng)。

配置webpack配置,增加ts的loader,如awesome-typescript-loader。(如果是基于atool-build來構(gòu)建的項(xiàng)目,則它內(nèi)置了ts編譯,這步省略)

loaders: [// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.{ test: /\.tsx?$/, loader: "awesome-typescript-loader" }]復(fù)制代碼

此時(shí)你可以寫文件名為ts和tsx(React)后綴的代碼了,它可以和現(xiàn)有的ES6代碼共存,VSCode會(huì)自動(dòng)校驗(yàn)這部分代碼,webpack打包也沒問題了。

逐漸的,開始打算重構(gòu)以前的ES6代碼為TS代碼,只需將文件后綴改成ts(x)就行,就可以享受TS及IDE智能感知/糾錯(cuò)帶來的好處。

更多遷移教程:官方遷移教程、官方React項(xiàng)目遷移教程、社區(qū)教程1、社區(qū)教程2。

新項(xiàng)目

對于新項(xiàng)目,微軟提供了非常棒的一些Starter項(xiàng)目,詳細(xì)介紹了如何用TS和其他框架、庫配合使用。如果是React項(xiàng)目,可以參考這個(gè)Starter:TypeScript-React-Starter

成本對比

星多表示占優(yōu)

成本點(diǎn)ESTS說明

學(xué)習(xí)和踩坑成本※※※※※※※※雖然是JS超集,但還是要學(xué)習(xí)TS本身及面向?qū)ο蠡A(chǔ)知識,開發(fā)環(huán)境搭建、使用中的問題和坑也需要自己趟,好在TS社區(qū)比較成熟,網(wǎng)上沉淀的資料很多

整體代碼量※※※※※※※※※TS代碼增加比較完善的類型定義的話整體代碼量比原生ES多5%~10%左右

原生JS(標(biāo)準(zhǔn)ES、瀏覽器端、服務(wù)器端)※※※※※※※※IDE內(nèi)置了詳盡的類型聲明,可以智能提示方法和參數(shù)說明,提升了效率

依賴外部庫(React、Lodash、Antd)※※※※※※※※有TS類型聲明庫,IDE智能提示和分析,效率提升

內(nèi)部公共庫、模塊※※※※※※※團(tuán)隊(duì)內(nèi)部自行編寫類型定義文件,有一定工作量,但開發(fā)效率可以有一些提升,逐步完善類型定義后,效率進(jìn)一步提升

團(tuán)隊(duì)協(xié)作效率※※※※※※※對系統(tǒng)配置、外部接口、內(nèi)部模塊做類型定義后,實(shí)例對象屬性就不能隨意改了,每個(gè)被調(diào)用方負(fù)責(zé)自己的對外類型展現(xiàn)(可以理解為形狀),調(diào)用者只需關(guān)心被調(diào)用方的類型,不需關(guān)心內(nèi)部細(xì)節(jié)

代碼可維護(hù)性※※※※※※由于團(tuán)隊(duì)成員水平差異,和軟件的的特質(zhì),長期迭代維護(hù)的項(xiàng)目總會(huì)遇到可維護(hù)性的問題,有了強(qiáng)類型約束和靜態(tài)檢查,以及智能IDE的幫助下,可以降低軟件腐化的速度,提升可維護(hù)性,且在重構(gòu)時(shí),強(qiáng)類型和靜態(tài)類型檢查會(huì)幫上大忙,甚至有了類型定義,會(huì)不經(jīng)意間增加重構(gòu)的頻率

運(yùn)行時(shí)穩(wěn)定性※※※※※※由于TS有靜態(tài)類型檢查,很多bug都會(huì)被消滅在上線前

小結(jié)

從上面的對比中可以看到,使用大家都熟悉的ES作為開發(fā)語言只在學(xué)習(xí)和踩坑成本以及整體代碼量上占優(yōu),如果只是短期項(xiàng)目,那用ES無可厚非,但我們的項(xiàng)目生命周期持續(xù)好幾年,是持續(xù)迭代升級的,目前TS社區(qū)已經(jīng)比較成熟,學(xué)習(xí)資料也很多,而且TS帶來的是內(nèi)部協(xié)作開發(fā)效率、可維護(hù)性、穩(wěn)定性的提升,所以從長遠(yuǎn)來看這個(gè)代價(jià)是值得付出的。而且各種類型聲明定義文件的存在,是可以提升開發(fā)效率的;而且靜態(tài)類型檢查可以減少bug數(shù)量和排查bug的難度,變相也提升了效率,而且使整個(gè)項(xiàng)目相對變得更為穩(wěn)定可控。

社區(qū)發(fā)展

從Stackoverflow的2017年開發(fā)者調(diào)查報(bào)告、Google趨勢npm下載量趨勢上可以到看,TypeScript社區(qū)發(fā)展很快,特別是最近幾年。特別是伴隨著VS Code的誕生(TS寫的,對TS支持非常友好),VS Code + TypeScript的組合讓前端圈產(chǎn)生了一股清流,生產(chǎn)力和規(guī)范性得到了快速提升。從Google對TS的支持(Angular高于2的版本是TS寫的)看到,國際大廠也是支持的。

從螞蟻集團(tuán)內(nèi)部看,Ant Design、Basement等產(chǎn)品也是基于TS寫的(至少是在大量使用),雖然有一些反對的聲音,但總體還是看好的,有合適的土壤就會(huì)快速發(fā)展,如Ant Design。

周邊生態(tài)

類型聲明包

React、及其他各種著名框架、庫都有TS類型聲明,我們可以在項(xiàng)目中通過npm install @types/react方式安裝,可以在這個(gè)網(wǎng)站搜索你想要安裝的庫聲明包。安裝后,寫和那些框架、庫相關(guān)的代碼將會(huì)是一種非常爽的體驗(yàn),函數(shù)的定義和注釋將會(huì)自動(dòng)提示出來,開發(fā)效率將會(huì)得到提升。

IDE

VS Code、WebStorm等前端圈流行的IDE都對TS有著非常友好的支持,VS Code甚至自身就是TS寫成的。

深入解讀TS

TS語言設(shè)計(jì)目標(biāo)

目標(biāo)

編譯期可以做靜態(tài)檢查,為大規(guī)模代碼提供結(jié)構(gòu)化裝置,編譯出符合習(xí)慣、易讀的JS代碼,和ECMAScript標(biāo)準(zhǔn)對齊,使用一貫的、可刪除的、結(jié)構(gòu)化的類型系統(tǒng),保護(hù)編譯后的JS代碼的運(yùn)行時(shí)行為等等。

非目標(biāo)

模仿現(xiàn)有語言,優(yōu)化編譯后代碼的性能,應(yīng)用“正確”的類型系統(tǒng),增加運(yùn)行時(shí)類型信息等等。

TS設(shè)計(jì)目標(biāo)原文

TS簡史

在最近幾年,隨著V8平臺、各大現(xiàn)代瀏覽器的起來,JS的運(yùn)行平臺再不斷完善,但,JS對于大型應(yīng)用的開發(fā)是非常困難的,JS語言設(shè)計(jì)出來的目的不是為了大型應(yīng)用,他是一門腳本語言,他沒有靜態(tài)類型校驗(yàn),但更重要的是,他沒有提供大型應(yīng)用必須的classes、modules/namespaces、interfaces等結(jié)構(gòu)化的裝置,中間也出來過GWT等為了其他語言開發(fā)者開發(fā)大型JS應(yīng)用的項(xiàng)目,這些項(xiàng)目可以讓你利用Java等面向?qū)ο笳Z言開發(fā)大型Web應(yīng)用,也可以利用到Eclipse等好用的IDE,但這些項(xiàng)目不是用JS寫代碼,所以如果你想用JS里的一些東西,你可能要比較費(fèi)勁的在其他語言里把它給實(shí)現(xiàn)出來,所以我們考慮如何增強(qiáng)JS語言,提供如靜態(tài)類型檢查、classes、modules/namespaces、interfaces等大型應(yīng)用裝置,這就是TS語言:**TS是一種開發(fā)大型JS應(yīng)用的語言,更詳細(xì)一點(diǎn)來說,TS是有類型的編譯到純JS的JS超集。**所以一般來說,JS代碼也是TS代碼。本身TS編譯器也是TS寫的,運(yùn)行Node.js環(huán)境?!?a target="_blank">Anders Hejlsberg: Introducing TypeScript 2012】

TS作者在最近微軟Build大會(huì)給出的一個(gè)圖:

如圖,Web和Node平臺的JS始終與JS最新規(guī)范有一段距離,Web平臺的距離更遠(yuǎn),TS可以填充這個(gè)間隙,讓使用者在Web和Node平臺都能用上最新的Feature,用上優(yōu)雅的JS,提高生產(chǎn)力?!?a target="_blank">Anders Hejlsberg: What's new in TypeScript? 2017】

和Flow 、Babel的對比

vs Flow

這篇文章可以看出,基礎(chǔ)的類型檢查功能發(fā)展到現(xiàn)在已經(jīng)差別不大了,但在周邊生態(tài)、文檔完整性、社區(qū)資源方面TS勝過Flow。

vs Babel

Babel也是很不錯(cuò)的ES6 to 5編譯工具,有不錯(cuò)的插件機(jī)制,社區(qū)發(fā)展也不錯(cuò),但在同樣一段代碼編譯出的JS代碼里可以看到,TS編譯后的代碼是更符合習(xí)慣、簡潔易讀一些(都用的是官方網(wǎng)站的Playground工具)。我曾經(jīng)維護(hù)過TS編譯后的JS代碼(TS源碼丟失),感覺還OK。

Babel編譯后:

>need-to-insert-img

TS編譯后:

TS基礎(chǔ)知識及核心概念

基礎(chǔ)類型

letisDone:boolean=false;letdecimal:number=6;letcolor:string="blue";// 數(shù)組,有兩種寫法letlist:number[] = [1,2,3];letlist:Array = [1,2,3];// 元組(Tuple)letx: [string,number] = ["hello",10];// 枚舉enumColor {Red =1, Green =2, Blue =4}letc: Color = Color.Green;// 不確定的可以先聲明為anyletnotSure:any=4;// 聲明沒有返回值functionwarnUser():void{? ? alert("This is my warning message");}letu:undefined=undefined;letn:null=null;// 類型永遠(yuǎn)沒返回functionerror(message:string):never{thrownewError(message);}// 類型主張,就是知道的比編譯器多,主動(dòng)告訴編譯器更多信息,有兩種寫法letsomeValue:any="this is a string";letstrLength:number= (someValue).length;letstrLength:number= (someValueasstring).length;復(fù)制代碼

更多介紹可以直接看官方文檔。

interface

TS中的一個(gè)核心原則之一就是類型檢查關(guān)注的是值的形狀,有時(shí)就叫做“鴨子辨型”(duck typing)或“結(jié)構(gòu)化子類型”(structural subtyping)。TS中interface就承擔(dān)了這樣的角色,定義形狀與約束,在內(nèi)部使用或者和外部系統(tǒng)協(xié)作。一個(gè)例子:

interfaceSystemConfig {? attr1:string;? attr2:number;? ? func1():string;? ? func2():void;}復(fù)制代碼

我們給軟件定了一個(gè)系統(tǒng)參數(shù)的配置接口,他定義了系統(tǒng)配置的形狀,有兩個(gè)屬性attr1和attr2,兩個(gè)方法func1和func2,這樣如果定義了const systemConfig: SystemConfig = {},那systemConfig就不能隨意修改了,他有形狀了。

在Java中,我們提倡面向接口編程,接口優(yōu)于抽象類【Effective Java】,在TS的類系統(tǒng)中,接口也可以承擔(dān)這樣的角色,我們可以用implements來實(shí)現(xiàn)接口,這樣可以實(shí)現(xiàn)類似更為靈活的繼承,如:

classAextendsBaseClassimplementsBaseInterface1, BaseInterface2 {}復(fù)制代碼

類A繼承了BaseClass,并且繼承了BaseInterface1和BaseInterface2兩個(gè)接口。

module/namespace

導(dǎo)出到外部的模塊寫法和ES6一樣,內(nèi)部模塊現(xiàn)在推薦用namespace,如:

namespaceModule1 {exportinterfaceSubModule1 {}exportinterfaceSubModule2 {}}constmodule: Module1.SubModule = {}復(fù)制代碼

命名空間在JS中用對象字面量也可以實(shí)現(xiàn),早些年的很多JS庫都是這種模式,但顯然有了這種顯示的命名空間聲明,代碼的易讀性更好,且不能隨意的改變,不像用原生JS對象時(shí)容易被覆蓋。

訪問權(quán)限控制

TS有著和傳統(tǒng)面向?qū)ο笳Z言類似的public、protected、private等訪問權(quán)限,這個(gè)在大型應(yīng)用中很實(shí)用,這里不展開。

其他

除了泛型相對難以掌握,其他class、decorator、async/await等都和ES6、ES7寫法類似。

Type和Type System

TypeScript = Type + Script,那么編程語言中的Type是怎么定義的呢?

Incomputer scienceandcomputer programming, adata typeor simplytypeis a classification of data which tells the compiler or interpreter how the programmer intends to use the data.【維基百科

在計(jì)算機(jī)科學(xué)中,數(shù)據(jù)類型或者簡單說類型,是數(shù)據(jù)的類別,用來告訴編譯器/解釋器程序員想怎么使用數(shù)據(jù)?;镜臄?shù)據(jù)類型如整數(shù)、布爾值、字符等,組合數(shù)據(jù)類型如數(shù)組、對象等,也有抽象數(shù)據(jù)類型如隊(duì)列、棧、集合、字典等等。數(shù)據(jù)類型用在類型系統(tǒng)中,類型系統(tǒng)提供了類型定義、實(shí)現(xiàn)和使用的方式,每種編程語言都有各自的類型系統(tǒng)實(shí)現(xiàn)(如果有的話)。

我們來看看Type System(類型系統(tǒng))的定義:

Inprogramming languages, atype systemis a set of rules that assigns a property calledtypeto the various constructs of acomputer program, such asvariables,expressions,functionsormodules.[1]These types formalize and enforce the (otherwise implicit) categories the programmer uses for data structures and components (ex: "string", "array of float", "function returning boolean"). The main purpose of a type system is to reduce possibilities forbugsin computer programs[2]by defining interfaces between different parts of a computer program, and then checking that the parts have been connected in a consistent way. 【維基百科

在編程語言中,類型系統(tǒng)是一個(gè)規(guī)則集合,給程序中的變量、表達(dá)式、函數(shù)、模塊等程序構(gòu)建元素分配叫做類型的屬性。這些類型明確并強(qiáng)制(也可能是含蓄的)程序員如何使用數(shù)據(jù)結(jié)構(gòu)。**類型系統(tǒng)的主要目的是通過定義程序不同部分間協(xié)作的接口,并檢查不同部分以始終如一的方式協(xié)作,來減少程序可能產(chǎn)生的bug。**這種檢查可能是靜態(tài)的(編譯期)或動(dòng)態(tài)的(運(yùn)行時(shí)),或者既有靜態(tài)的也有動(dòng)態(tài)的。

類型系統(tǒng)的好處

檢測錯(cuò)誤

The most obvious benefit of static typechecking is that it allows early detection of some programming errors. Errors that are detected early can be fixed immediately, rather than lurking in the code to be discovered much later,when the programmer is in the middle of something else—or even after the program has been deployed. Moreover, errors can often be pinpointed more accurately during typechecking than at run time, when their effects may not become visible until some time after things begin to go wrong.【Types and Programming Languages

As your app grows, you can catch a lot of bugs with typechecking. 【React typechecking

靜態(tài)類型檢查最明顯的好處是可以盡早的檢查出程序中的錯(cuò)誤。錯(cuò)誤被盡早的檢查出來可以使它得到快速的修復(fù),而不是潛伏在代碼中,在中期甚至部署上線后才被發(fā)現(xiàn)。而且,錯(cuò)誤在編譯期可以被更精確的定位出來,而在運(yùn)行時(shí),錯(cuò)誤產(chǎn)生的影響在程序出現(xiàn)問題前可能是不容易被發(fā)現(xiàn)的。

程序會(huì)有各種各樣的數(shù)據(jù)結(jié)構(gòu),如果改了一個(gè)數(shù)據(jù)類型,前端很多時(shí)候都是通過全局查找來處理這種重構(gòu)問題的。而靜態(tài)類型檢查則可以使再次編譯后就能探知所有可能的錯(cuò)誤,加上IDE的智能錯(cuò)誤提示,重構(gòu)起來更放心、更方便。

抽象化

Another important way in which type systems support the programming process is by enforcing disciplined programming. In particular, in the context of large-scale software composition, type systems form the backbone of the module languages used to package and tie together the components of large systems. Types show up in the interfaces of modules (and related structures such as classes); indeed, an interface itself can be viewed as “the type of a module,” providing a summary of the facilities provided by the module—a kind of partial contract between implementors and users.

Structuring large systems in terms of modules with clear interfaces leads to a more abstract style of design, where interfaces are designed and discussed independently from their eventual implementations. More abstract thinking about interfaces generally leads to better design.【Types and Programming Languages

類型系統(tǒng)支持編程階段的另外一個(gè)重要方式是強(qiáng)制讓編程遵守紀(jì)律。在大規(guī)模軟件系統(tǒng)中,類型系統(tǒng)組成了組件協(xié)作系統(tǒng)的脊梁。類型展現(xiàn)在模塊(或者相關(guān)的結(jié)構(gòu)如類)的接口中。接口可以看做“模塊的類型”,展示了模塊所能提供的功能,是一種實(shí)現(xiàn)者和用戶間的合約。

在大量模塊協(xié)作組成的大規(guī)模結(jié)構(gòu)化軟件系統(tǒng)中清晰的接口可以使設(shè)計(jì)更為抽象,接口的設(shè)計(jì)和討論獨(dú)立于它們的實(shí)現(xiàn)。一般來說,對接口更為抽象的思考可以使得做出更好的設(shè)計(jì)。

Types enable programmers to think at a higher level than the bit or byte, not bothering with low-level implementation. For example, programmers can begin to think of a string as a set of character values instead of as a mere array of bytes. Higher still, types enable programmers to think about and expressinterfacesbetween two ofany-sized subsystems. This enables more levels of localization so that the definitions required for interoperability of the subsystems remain consistent when those two subsystems communicate.【維基百科

類型會(huì)讓程序員在一個(gè)更高的維度思考,而不是在底層的計(jì)算機(jī)實(shí)現(xiàn)細(xì)節(jié)糾纏。例如,我們可以把字符串想成字符集,而不僅僅是比特?cái)?shù)組。更高維度,類型系統(tǒng)可以讓我們用接口來思考和表達(dá)任意子系統(tǒng)/子程序之間的協(xié)作,接口定義可以讓子系統(tǒng)/子程序之間的通信方式始終如一。

文檔化

Types are also useful when reading programs. The type declarations in procedure headers and module interfaces constitute a form of documentation,giving useful hints about behavior. Moreover, unlike descriptions embedded in comments, this form of documentation cannot become outdated, since itis checked during every run of the compiler. This role of types is particularly important in module signatures.【Types and Programming Languages

類型對于閱讀程序也是有用的。在程序頭部的類型聲明和模塊接口形成了文檔的形狀,提供程序的行為提示。此外,不同于在注釋中的描述,這種形式的文檔不會(huì)過期,因?yàn)槊看尉幾g都會(huì)校驗(yàn),這在模塊簽名里特別重要。

In more expressive type systems, types can serve as a form ofdocumentationclarifying the intent of the programmer. For example, if a programmer declares a function as returning a timestamp type, this documents the function when the timestamp type can be explicitly declared deeper in the code to be an integer type.【維基百科

在復(fù)用表現(xiàn)力的類型系統(tǒng)中,類型可以看做是一種描述程序員意圖的表述方式。例如,我們聲明一個(gè)函數(shù)返回一個(gè)時(shí)間戳,這樣就相當(dāng)于明確說明了這個(gè)函數(shù)在更深層次的代碼調(diào)用中會(huì)返回整數(shù)類型。

語言安全

The term “safe language” is, unfortunately, even more contentious than “type system.” Although people generally feel they know one when they see it, their notions of exactly what constitutes language safety are strongly influenced by the language community to which they belong. Informally, though, safelanguages can be defined as ones that make it impossible to shoot yourself in the foot while programming.【Types and Programming Languages

安全語言這個(gè)說法是有爭議的。受到該語言社區(qū)的嚴(yán)重影響。不正式的來說,安全語言可以被定義為在編程時(shí)不可能從底層把自己殺死。

A type system enables thecompilerto detect meaningless or probably invalid code. For example, we can identify an expression3 / "Hello, World"as invalid, when the rules do not specify how to divide anintegerby astring. Strong typing offers more safety, but cannot guarantee completetype safety.【維基百科

類型系統(tǒng)會(huì)允許編譯器檢查無意義或者可能不合法的代碼。例如,我們知道3/'hello world'不合法,強(qiáng)類型提供了更多的安全性,但也不能完全做到類型安全。

效率

Static type-checking may provide useful compile-time information. For example, if a type requires that a value must align in memory at a multiple of four bytes, the compiler may be able to use more efficient machine instructions.【維基百科

靜態(tài)類型檢查會(huì)提供有用的編譯期信息。例如,如果一個(gè)類型需要在內(nèi)存中占四個(gè)字節(jié),編譯器可能會(huì)使用更有效率的機(jī)器指令。

靜態(tài)類型、動(dòng)態(tài)類型和弱類型、強(qiáng)類型

靜態(tài)類型:編譯期就知道每一個(gè)變量的類型。類型錯(cuò)誤編譯失敗是語法問題。如Java、C++。

動(dòng)態(tài)類型:編譯期不知道類型,運(yùn)行時(shí)才知道。類型錯(cuò)誤拋出異常發(fā)生在運(yùn)行時(shí)。如JS、Python。

弱類型:容忍隱式類型轉(zhuǎn)換。如JS,1+'1'='11',數(shù)字型轉(zhuǎn)成了字符型。

強(qiáng)類型:不容忍隱式類型轉(zhuǎn)換。如Python,1+'1'會(huì)拋出TypeError。

接受TS

TS剛出來時(shí)我是有點(diǎn)抵觸的,或者對她的感覺就跟和CoffeeScript、Dart等編譯到JS語言差不多,感覺就是其他語言往JS滲透的產(chǎn)物,近一兩年,社區(qū)中TS的聲音越來越強(qiáng),而我也開始做大型JavaScript應(yīng)用,隨之逐漸重新認(rèn)識TS,逐漸認(rèn)識到TS的類型系統(tǒng)、TSC的靜態(tài)檢查、VS Code等IDE的強(qiáng)力支持對于開發(fā)出可維護(hù)性好、穩(wěn)定性高的大型JavaScript應(yīng)用的重要性。

權(quán)衡

如何更好的利用JS的動(dòng)態(tài)性和TS的靜態(tài)特質(zhì),我們需要結(jié)合項(xiàng)目的實(shí)際情況來進(jìn)行綜合判斷。一些建議:

如果是中小型項(xiàng)目,且生命周期不是很長,那就直接用JS吧,不要被TS束縛住了手腳。

如果是大型應(yīng)用,且生命周期比較長,那建議試試TS。開源項(xiàng)目如VS Code、GitHub桌面端,不開源的如Slack桌面端、Asana、Palantir

如果是框架、庫之類的公共模塊,那更建議用TS了。如Ant Design、Angular、Ionic

至于到底用不用TS,還是要看實(shí)際項(xiàng)目規(guī)模、項(xiàng)目生命周期、團(tuán)隊(duì)規(guī)模、團(tuán)隊(duì)成員情況等實(shí)際情況綜合考慮。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容