恭喜你選擇 TypeScript 作為你的首選語言之一——你已經做出了明智的選擇!
你可能已經聽說過 TypeScript 是 JavaScript 的一種“口味”或“變體”。在現代程式語言中,TypeScript (TS) 與 JavaScript (JS) 之間的關係相當獨特,因此深入瞭解這種關係將有助於你理解 TypeScript 是如何增強 JavaScript 的。
什麼是 JavaScript?簡要歷史
JavaScript(也稱為 ECMAScript)最初是作為瀏覽器的一種簡單指令碼語言而誕生的。在它發明之初,人們預期它僅用於網頁中嵌入的簡短程式碼片段——編寫幾十行以上的程式碼在當時是相當少見的。因此,早期的 Web 瀏覽器執行此類程式碼的速度非常慢。然而,隨著時間的推移,JS 變得越來越流行,Web 開發人員開始使用它來建立互動式體驗。
Web 瀏覽器開發者透過最佳化其執行引擎(動態編譯)和擴充套件其功能(新增 API)來響應 JS 使用量的增加,這反過來又促使 Web 開發者更多地使用它。在現代網站上,你的瀏覽器經常執行著跨越數十萬行程式碼的應用程式。這是“網路”漫長而漸進的發展歷程,它從一個簡單的靜態頁面網路演變成了一個承載各種豐富應用程式的平臺。
不僅如此,JS 已經變得足夠流行,可以在瀏覽器環境之外使用,例如使用 node.js 實現 JS 伺服器。“隨處執行”的 JS 特性使其成為跨平臺開發的理想選擇。如今,許多開發人員只使用 JavaScript 來編寫他們的整個技術棧!
總結一下,這門語言最初是為快速使用而設計的,後來成長為編寫數百萬行程式碼應用程式的完整工具。每種語言都有自己的怪癖——即奇特之處和意外,JavaScript 卑微的開端導致它擁有許多這樣的怪癖。以下是一些例子:
-
JavaScript 的相等運算子 (
==) 會對其運算元進行強制型別轉換,從而導致意外行為jsif ("" == 0) {// It is! But why??}if (1 < x < 3) {// True for *any* value of x!} -
JavaScript 還允許訪問不存在的屬性
jsconst obj = { width: 10, height: 15 };// Why is this NaN? Spelling is hard!const area = obj.width * obj.heigth;
大多數程式語言在出現此類錯誤時會丟擲錯誤,有些甚至會在編譯階段(程式碼執行之前)就進行報錯。在編寫小程式時,這些怪癖雖然令人討厭但尚可應付;而在編寫成百上千行程式碼的應用程式時,這些不斷出現的意外就會成為嚴重的問題。
TypeScript:靜態型別檢查器
我們之前說過,有些語言根本不允許這些有錯誤的程式碼執行。在不執行程式碼的情況下檢測錯誤被稱為靜態檢查。根據操作值的型別來確定是否為錯誤,這被稱為靜態型別檢查。
TypeScript 在程式執行前對其進行檢查,並根據值的型別進行檢查,因此它是一個靜態型別檢查器。例如,上面最後一個示例中存在錯誤,原因在於 obj 的型別。這是 TypeScript 發現的錯誤:
tsTryconstobj = {width : 10,height : 15 };constProperty 'heigth' does not exist on type '{ width: number; height: number; }'. Did you mean 'height'?2551Property 'heigth' does not exist on type '{ width: number; height: number; }'. Did you mean 'height'?area =obj .width *obj .; heigth
JavaScript 的型別化超集
那麼,TypeScript 與 JavaScript 是什麼關係呢?
語法
TypeScript 是一門 JavaScript 的超集:因此,JS 語法即是合法的 TS 語法。語法指的是我們編寫文字以構成程式的方式。例如,這段程式碼因為缺少一個 ) 而存在語法錯誤
tsTrylet')' expected.1005')' expected.a = (4
TypeScript 不會將任何 JavaScript 程式碼視為語法錯誤。這意味著你可以將任何有效的 JavaScript 程式碼放入 TypeScript 檔案中,而不必擔心它的編寫方式。
型別
然而,TypeScript 是一個型別化的超集,這意味著它增加了關於如何使用不同型別值的規則。之前關於 obj.heigth 的錯誤不是語法錯誤:它是以錯誤的方式使用某種值(型別)的錯誤。
再舉一個例子,這是你可以在瀏覽器中執行的 JavaScript 程式碼,它會記錄一個值
jsconsole.log(4 / []);
這個語法合法的程式會記錄 Infinity。然而,TypeScript 認為用陣列除以數字是一種毫無意義的操作,因此會發出錯誤。
tsTryThe right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.2363The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.console .log (4 /[] );
有可能你確實打算用數字除以陣列,也許只是為了看看會發生什麼,但大多數情況下,這都是一個程式設計錯誤。TypeScript 的型別檢查器旨在允許正確的程式透過,同時儘可能多地捕獲常見錯誤。(稍後,我們將學習如何配置 TypeScript 對程式碼的檢查嚴格程度。)
如果你將某些程式碼從 JavaScript 檔案移動到 TypeScript 檔案中,你可能會看到型別錯誤,具體取決於程式碼的編寫方式。這些可能是程式碼中的合法問題,或者是 TypeScript 過於保守。在本指南中,我們將演示如何新增各種 TypeScript 語法來消除此類錯誤。
執行時行為
TypeScript 也是一種保留 JavaScript 執行時行為的程式語言。例如,在 JavaScript 中,除以零會產生 Infinity,而不是丟擲執行時異常。作為原則,TypeScript 永遠不會改變 JavaScript 程式碼的執行時行為。
這意味著如果你將程式碼從 JavaScript 移動到 TypeScript,即使 TypeScript 認為程式碼有型別錯誤,它也保證能以相同的方式執行。
保持與 JavaScript 相同的執行時行為是 TypeScript 的一項基本承諾,這意味著你可以輕鬆地在兩種語言之間轉換,而不必擔心會導致程式無法執行的細微差異。
型別擦除
粗略地說,一旦 TypeScript 編譯器完成對程式碼的檢查,它就會擦除型別以生成最終的“編譯後”程式碼。這意味著一旦程式碼編譯完成,生成的普通 JS 程式碼中就不包含任何型別資訊。
這也意味著 TypeScript 永遠不會根據它推斷出的型別來改變你程式的行為。歸根結底,雖然你在編譯時可能會看到型別錯誤,但型別系統本身對程式執行時的運作方式沒有任何影響。
最後,TypeScript 不提供任何額外的執行時庫。你的程式將使用與 JavaScript 程式相同的標準庫(或外部庫),因此不需要學習任何特定於 TypeScript 的框架。
學習 JavaScript 和 TypeScript
我們經常看到這樣的問題:“我應該學習 JavaScript 還是 TypeScript?”。
答案是:不學習 JavaScript 就無法學習 TypeScript!TypeScript 與 JavaScript 共享語法和執行時行為,因此你學習 JavaScript 的任何知識都在同時幫助你學習 TypeScript。
程式設計師可以學習 JavaScript 的資源非常多;如果你在編寫 TypeScript,不應忽略這些資源。例如,StackOverflow 上標記為 javascript 的問題大約是 typescript 的 20 倍,但所有 javascript 問題也適用於 TypeScript。
如果你發現自己在搜尋類似“如何在 TypeScript 中對列表進行排序”之類的內容,請記住:TypeScript 就是帶有編譯時型別檢查器的 JavaScript 執行時。你在 TypeScript 中對列表排序的方式與在 JavaScript 中相同。如果你找到的資源直接使用了 TypeScript,那當然也很好,但不要侷限於認為在處理日常執行時任務時,必須尋找特定於 TypeScript 的答案。
後續步驟
這是對日常 TypeScript 中使用的語法和工具的簡要概述。從這裡開始,您可以
-
學習一些 JavaScript 基礎知識,我們推薦以下資源:
-
閱讀完整手冊 從頭到尾