本書適合各類程序員閱讀,例如JavaScript 專業(yè)工程師、C# 從業(yè)者、Java 擁護(hù)者、Python 愛(ài)好者、Ruby 偏愛(ài)者和Haskell 支持者。不管你使用什么編程語(yǔ)言,只要有一定的編程經(jīng)驗(yàn),了解函數(shù)、變量、類和錯(cuò)誤等基礎(chǔ)知識(shí),就可以閱讀這本書。如果你使用過(guò)JavaScript,有文檔對(duì)象模型(DocumentObject Model,DOM)和網(wǎng)絡(luò)編程經(jīng)驗(yàn),那就更好了。本書雖然沒(méi)有深入探討這些概念,但是將從這些方面舉例。如果你不熟悉這些概念,可能無(wú)法深入領(lǐng)會(huì)示例的意圖。
無(wú)論使用哪一門編程語(yǔ)言,我們都有共同的經(jīng)歷。為了追查異常,我們一行一行分析代碼,找出問(wèn)題所在,各個(gè)擊破。而TypeScript 能助我們一臂之力,它會(huì)自動(dòng)檢查代碼,指出那些逃過(guò)我們眼睛的錯(cuò)誤。
如果你沒(méi)使用過(guò)靜態(tài)類型語(yǔ)言也沒(méi)關(guān)系。筆者將教你類型的知識(shí),告訴你如何使用類型減少程序崩潰的可能、提升代碼的語(yǔ)義,便于多位工程師共同維護(hù),也讓應(yīng)用能惠及更多的用戶,能在多臺(tái)服務(wù)器上彈性伸縮。在行文上,筆者將力求淺顯易懂,以直觀、易記的方式講解相關(guān)概念,從實(shí)用角度出發(fā),通過(guò)大量示例把抽象的問(wèn)題講清楚。
與其他類型語(yǔ)言相比,TypeScript 的特點(diǎn)是非常注重實(shí)用。TypeScript 發(fā)明了一套全新的概念,保證代碼簡(jiǎn)潔、準(zhǔn)確,使編寫應(yīng)用的過(guò)程充滿樂(lè)趣,更符合現(xiàn)代標(biāo)準(zhǔn),也更安全。
內(nèi)容結(jié)構(gòu)
本書有兩個(gè)目的:一是深入講解TypeScript 語(yǔ)言的原理(理論層面);二是給出大量實(shí)用的建議,助你寫出更好的TypeScript 代碼(應(yīng)用層面)。
前面說(shuō)過(guò),TypeScript 是一門注重實(shí)用的語(yǔ)言,理論與應(yīng)用往往是聯(lián)系在一起的。本書多數(shù)篇幅將穿插講解這兩方面,不過(guò)前幾章基本只講理論,后幾章則幾乎只說(shuō)具體應(yīng)用。
本書首先介紹編譯器、類型檢查器和類型的基礎(chǔ)知識(shí)。然后,分別說(shuō)明TypeScript 中不同類型和類型運(yùn)算符的作用和用法。掌握這些基礎(chǔ)之后,可以深入探討一些高級(jí)話題,比如TypeScript 最為復(fù)雜的類型系統(tǒng)特性、錯(cuò)誤處理和異步編程。最后,說(shuō)明怎樣結(jié)合你最喜歡的框架(前端和后端)使用TypeScript,如何把現(xiàn)有的JavaScript 項(xiàng)目遷移到TypeScript,以及如何在生產(chǎn)環(huán)境下運(yùn)行TypeScript 應(yīng)用。
本書每章的末尾都有練習(xí)題,請(qǐng)你嘗試自己解答,這樣才能更深入地領(lǐng)會(huì)所講的內(nèi)容。練習(xí)題的參考答案在網(wǎng)上,地址為https://github.com/bcherny/programming-typescript-answers。
代碼風(fēng)格
本書盡量一以貫之,使用同一種代碼風(fēng)格。筆者采用的代碼風(fēng)格有一部分帶有強(qiáng)烈的個(gè)人風(fēng)格,例如:
?? 只在必要時(shí)使用分號(hào)。
?? 使用兩個(gè)空格縮進(jìn)。
?? 在簡(jiǎn)單的代碼片段中,或者程序的結(jié)構(gòu)比細(xì)節(jié)重要時(shí),使用簡(jiǎn)短的名稱命名變量,例如a、f 或_。
本書使用的編程風(fēng)格,有一部分也建議你采用。比如說(shuō):
?? 應(yīng)該使用最新的JavaScript 句法和特性(最新版JavaScript 通常稱為“esnext”)。這樣能讓代碼符合最新的標(biāo)準(zhǔn),提升代碼的互操作性,便于搜索,也能減少新員工的前期投入時(shí)間。此外,還可以充分利用JavaScript 的新特性,例如箭頭函數(shù)、promise 和生成器。
?? 盡量使用展開(kāi)運(yùn)算符(...),保持?jǐn)?shù)據(jù)結(jié)構(gòu)不可變。注1
?? 所有值都要有類型,不過(guò)盡量推導(dǎo)而出。切記不要濫用顯式類型,讓類型錯(cuò)誤暴露出來(lái),從而保證代碼簡(jiǎn)潔、增加安全。
?? 保證代碼的可用性和普適性。多態(tài)(見(jiàn)4.2 節(jié))是個(gè)有力的工具。
當(dāng)然,這些思想都是全新的。不過(guò),沿用這些風(fēng)格對(duì)TypeScript 的正常運(yùn)作有至關(guān)重要的作用。TypeScript 內(nèi)置的下層編譯器支持只讀類型,有強(qiáng)大的類型推導(dǎo)功能,深置對(duì)多態(tài)的支持,而且具有完整的結(jié)構(gòu)化類型系統(tǒng),這些都促使我們使用良好的編程風(fēng)格。與底層的JavaScript 相比,TypeScript 在語(yǔ)言層面上仍不失表現(xiàn)力和真實(shí)性。
在進(jìn)入正文之前,還有幾點(diǎn)要說(shuō)明。
JavaScript 沒(méi)有指針和引用的概念,有的只是值和引用類型。值是不可變的,包括字符串、數(shù)字和布爾值;而引用通常指向可變的數(shù)據(jù)結(jié)構(gòu),例如數(shù)組、對(duì)象和函數(shù)。本書中出現(xiàn)的“值”,一般不使用它的嚴(yán)格定義,而是指JavaScript 值或引用。
注1: 以防你沒(méi)接觸過(guò) JavaScript,舉個(gè)例子:假如有個(gè)對(duì)象 o ,我們想為該對(duì)象添加一個(gè)值為3 的屬性 k;為此,可以直接修改 o,使用o.k = 3 句法,也可以使用 let p ={...o, k: 3} 句法,新建一個(gè)對(duì)象。
最后,在與JavaScript 互操作時(shí),使用未嚴(yán)格遵守類型規(guī)定的第三方庫(kù)時(shí),維護(hù)舊代碼或匆匆上手時(shí),很容易寫出不太理想的TypeScript 代碼。本書的主要目的是教你如何正確編寫TypeScript,告誡你一定要遵守規(guī)則。但在實(shí)際中,怎么編寫代碼才算正確要看你自己或你的團(tuán)隊(duì)。
本書約定
本書采用下述排版約定。
斜體(Italic)
表示新術(shù)語(yǔ)、URL、電子郵件地址、文件名和擴(kuò)展名。
等寬字體(Constant Width)
表示程序清單,在段落中出現(xiàn)則表示程序元素,例如變量、函數(shù)名、數(shù)據(jù)類型、環(huán)境變量、語(yǔ)句和關(guān)鍵字。
斜體等寬字體(Constant Width Italic)
表示應(yīng)該替換成用戶提供的值,或者由上下文決定的值。
使用代碼示例
本書的補(bǔ)充材料(代碼示例、練習(xí)題等)可到https://github.com/bcherny/programming-typescript-answers 下載。
本書是幫你完成工作的。一般來(lái)說(shuō),如果本書提供了示例代碼,你可以把它用在你的程序或文檔中。除非你使用了很大一部分代碼,否則無(wú)需獲得許可。比如,用本書的幾個(gè)代碼片段寫一個(gè)程序就無(wú)需獲得許可,銷售或分發(fā)O’Reilly 圖書的示例光盤則需要獲得許可;引用本書中的示例代碼回答問(wèn)題無(wú)需獲得許可,將書中大量的代碼放到你的產(chǎn)品文檔中則需要獲得許可。
我們很希望但并不強(qiáng)制要求你在引用本書內(nèi)容時(shí)加上引用說(shuō)明。引用說(shuō)明一般包括書名、作者、出版社和ISBN。比如:“Programming TypeScript by Boris Cherny (O’Reilly). Copyright 2019 Boris Cherny, 978-1-492-03765-1.”。
如果你覺(jué)得自己對(duì)示例代碼的用法超出了上述許可的范圍, 請(qǐng)通過(guò)
permissions@oreilly.com 與我們聯(lián)系。
O’Reilly Online Learning
40 年間,O’Reilly Media 為眾多公司提供技術(shù)和商業(yè)培
訓(xùn),提升知識(shí)儲(chǔ)備和洞察力,為企業(yè)的成功助力。
我們有一群獨(dú)家專家和創(chuàng)新者,他們通過(guò)圖書、文章、會(huì)議和在線學(xué)習(xí)平臺(tái)分享知識(shí)和技術(shù)。O’Reilly 的在線學(xué)習(xí)平臺(tái)提供按需訪問(wèn)的直播培訓(xùn)課程、詳細(xì)的學(xué)習(xí)路徑、交互式編程環(huán)境,以及由O’Reilly 和其他200 多家出版社出版的書籍和視頻。詳情請(qǐng)?jiān)L問(wèn)http://oreilly.com。
聯(lián)系我們
任何有關(guān)本書的意見(jiàn)或疑問(wèn),請(qǐng)按照以下地址聯(lián)系出版社。
美國(guó):
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
中國(guó):
北京市西城區(qū)西直門南大街2 號(hào)成銘大廈C 座807 室(100035)
奧萊利技術(shù)咨詢(北京)有限公司
勘誤、示例和其他信息可到https://oreil.ly/programming-typescript 上獲取。
對(duì)本書的評(píng)論或技術(shù)疑問(wèn),可以發(fā)電子郵件到bookquestions@oreilly.com。
欲了解本社圖書、課程、會(huì)議和新聞等更多信息,請(qǐng)?jiān)L問(wèn)我們的網(wǎng)站http://www.oreilly.com。
我們的Facebook:http://facebook.com/oreilly。
我們的Twitter:http://twitter.com/oreillymedia。
我們的YouTube:http://www.youtube.com/oreillymedia。
致謝
幾年間斷斷續(xù)續(xù)的寫作和涂涂畫畫,加上一年的早起晚睡,以及周末和節(jié)假日的奮筆疾書,這本書才得以出版。
感謝O’Reilly 策劃這樣一本書,感謝編輯Angela Rufino 在整個(gè)過(guò)程中給予我的支持。感謝Nick Nance 對(duì)9.2 節(jié)的貢獻(xiàn),感謝Shyam Seshadri 對(duì)9.1.2 節(jié)的貢獻(xiàn)。感謝技術(shù)編輯Daniel Rosenwasser,他是TypeScript 團(tuán)隊(duì)的一員,用了很多時(shí)間閱讀草稿,指導(dǎo)我弄清了TypeScript 類型系統(tǒng)的方方面面。感謝Jonathan Creamer、Yakov Fain、Paul Buying 和Rachel Head 對(duì)本書做技術(shù)編輯、提供反饋。感謝我的家人Liza、Ilya、Vadim、Roza、Alik、Faina 和Yosif,感謝他們鼓勵(lì)才能使我堅(jiān)持完成這個(gè)項(xiàng)目。
感謝我的伴侶Sara Gilford,在撰寫本書的過(guò)程中她始終支持我,即使取消了周末計(jì)劃、寫作和編程到深夜,她也沒(méi)有怨言,而且主動(dòng)與我討論類型系統(tǒng)的復(fù)雜細(xì)節(jié)。如果沒(méi)有你,我不可能寫完這本書,你的支持讓我銘記終生。
前言 1
第1 章 導(dǎo)言 9
第2 章 TypeScript 概述 . 13
2.1 編譯器 .13
2.2 類型系統(tǒng) 15
TypeScript VS. JavaScript.16
2.3 代碼編輯器設(shè)置 20
2.3.1 tsconfig.json .20
2.3.2 tslint.json .22
2.4 index.ts 23
2.5 練習(xí)題 .24
第3 章 類型全解 26
3.1 類型術(shù)語(yǔ) 27
3.2 類型淺談 28
3.2.1 any .28
3.2.2 unknown 30
3.2.3 boolean 30
3.2.4 number .32
3.2.5 bigint .33
3.2.6 string 34
3.2.7 symbol .34
3.2.8 對(duì)象 .35
3.2.9 中場(chǎng)休息:類型別名、并集和交集.42
3.2.10 數(shù)組 .46
3.2.11 元組 .48
3.2.12 null、undefined、void 和never .51
3.2.13 枚舉 .53
3.3 小結(jié) .58
3.4 練習(xí)題 .58
第4 章 函數(shù) 60
4.1 聲明和調(diào)用函數(shù) 60
4.1.1 可選和默認(rèn)的參數(shù) .62
4.1.2 剩余參數(shù)64
4.1.3 call、apply 和bind 65
4.1.4 注解this 的類型 66
4.1.5 生成器函數(shù) 68
4.1.6 迭代器 .70
4.1.7 調(diào)用簽名72
4.1.8 上下文類型推導(dǎo) 75
4.1.9 函數(shù)類型重載 76
4.2 多態(tài) .83
4.2.1 什么時(shí)候綁定泛型 .88
4.2.2 可以在什么地方聲明泛型 .89
4.2.3 泛型推導(dǎo)91
4.2.4 泛型別名93
4.2.5 受限的多態(tài) 95
4.2.6 泛型默認(rèn)類型 100
4.3 類型驅(qū)動(dòng)開(kāi)發(fā) 101
4.4 小結(jié) .102
4.5 練習(xí)題 .103
第5 章 類和接口 104
5.1 類和繼承 104
5.2 super 110
5.3 以this 為返回類型 . 111
5.4 接口 . 113
5.4.1 聲明合并 115
5.4.2 實(shí)現(xiàn) . 117
5.4.3 實(shí)現(xiàn)接口還是擴(kuò)展抽象類 . 119
5.5 類是結(jié)構(gòu)化類型 120
5.6 類既聲明值也聲明類型 .121
5.7 多態(tài) .124
5.8 混入 .125
5.9 裝飾器 .129
5.10 模擬final 類 .132
5.11 設(shè)計(jì)模式 133
5.11.1 工廠模式 133
5.11.2 建造者模式 134
5.12 小結(jié) .136
5.13 練習(xí)題 .136
第6 章 類型進(jìn)階 138
6.1 類型之間的關(guān)系 139
6.1.1 子類型和超類型 139
6.1.2 型變 .141
6.1.3 可賦值性148
6.1.4 類型拓寬149
6.1.5 細(xì)化 .154
6.2 全面性檢查 159
6.3 對(duì)象類型進(jìn)階 161
6.3.1 對(duì)象類型的類型運(yùn)算符 .161
6.3.2 Record 類型 .166
6.3.3 映射類型167
6.3.4 伴生對(duì)象模式 170
6.4 函數(shù)類型進(jìn)階 171
6.4.1 改善元組的類型推導(dǎo) .171
6.4.2 用戶定義的類型防護(hù)措施 .172
6.5 條件類型 174
6.5.1 條件分配175
6.5.2 infer 關(guān)鍵字 .177
6.5.3 內(nèi)置的條件類型 178
6.6 解決辦法 179
6.6.1 類型斷言179
6.6.2 非空斷言180
6.6.3 明確賦值斷言 183
6.7 模擬名義類型 184
6.8 安全地?cái)U(kuò)展原型 187
6.9 小結(jié) .189
6.10 練習(xí)題 .190
第7 章 處理錯(cuò)誤 192
7.1 返回null 193
7.2 拋出異常 194
7.3 返回異常 197
7.4 Option 類型 199
7.5 小結(jié) .206
7.6 練習(xí)題 .207
第8 章 異步編程、并發(fā)和并行 . 208
8.1 JavaScript 的事件循環(huán) .209
8.2 處理回調(diào) 211
8.3 promise:讓一切回到正軌 214
8.4 async 和await 219
8.5 異步流 .220
事件發(fā)射器.221
8.6 多線程類型安全 224
8.6.1 在瀏覽器中:使用Web 職程.224
8.6.2 在NodeJS 中:使用子進(jìn)程 .234
8.7 小結(jié) .235
8.8 練習(xí)題 .236
第9 章 前后端框架 237
9.1 前端框架 237
9.1.1 React 239
9.1.2 Angular 6/7 246
9.2 類型安全的API .250
9.3 后端框架 252
9.4 小結(jié) .253
第10 章 命名空間和模塊 254
10.1 JavaScript 模塊簡(jiǎn)史 .255
10.2 import、export .258
10.2.1 動(dòng)態(tài)導(dǎo)入 259
10.2.2 使用CommonJS 和AMD 模塊 262
10.2.3 模塊模式與腳本模式 .262
10.3 命名空間 263
10.3.1 沖突 .265
10.3.2 編譯輸出 266
10.4 聲明合并 268
10.5 小結(jié) .269
10.6 練習(xí)題 .270
第11 章 與JavaScript 互操作 271
11.1 類型聲明 272
11.1.1 外參變量聲明 275
11.1.2 外參類型聲明 277
11.1.3 外參模塊聲明 278
11.2 逐步從JavaScript 遷移到TypeScript .280
11.2.1 第一步:添加TSC 280
11.2.2 第二步(上):對(duì)JavaScript 代碼做類型檢查(可選) 281
11.2.3 第二步(下):添加JSDoc 注解(可選) .283
11.2.4 第三步:把文件重命名為.ts .284
11.2.5 第四步:嚴(yán)格要求 .285
11.3 尋找JavaScript 代碼的類型信息 .286
11.4 使用第三方JavaScript .289
11.4.1 自帶類型聲明的JavaScript 289
11.4.2 DefinitelyTyped 中有類型聲明的JavaScript 290
11.4.3 DefinitelyTyped 中沒(méi)有類型聲明的JavaScript 290
11.5 小結(jié) .292
第12 章 構(gòu)建和運(yùn)行TypeScript . 293
12.1 構(gòu)建TypeScript 項(xiàng)目 .293
12.1.1 項(xiàng)目結(jié)構(gòu) 293
12.1.2 構(gòu)建產(chǎn)物 294
12.1.3 設(shè)置編譯目標(biāo) 295
12.1.4 生成源碼映射 300
12.1.5 項(xiàng)目引用 300
12.1.6 監(jiān)控錯(cuò)誤 303
12.2 在服務(wù)器中運(yùn)行TypeScript .304
12.3 在瀏覽器中運(yùn)行TypeScript .304
12.4 把TypeScript 代碼發(fā)布到NPM 中 307
12.5 三斜線指令 308
12.5.1 types 指令 309
12.5.2 amd-module 指令 .310
12.6 小結(jié) . 311
第13 章 總結(jié) 313
附錄A 類型運(yùn)算符 . 315
附錄B 實(shí)用類型 317
附錄C 限定作用范圍的聲明 . 319
附錄D 為第三方JavaScript 模塊編寫聲明文件的
技巧 321
附錄E 三斜線指令 . 329
附錄F 安全相關(guān)的TSC 編譯器標(biāo)志 . 331
附錄G TSX . 333