轉職成爲TypeScript程序員的參考手冊

寫在前面

做者並無任何能夠做爲背書的履從來證實本身寫做這份手冊的份量。 html

其內容大都來自於TypeScript官方資料或者搜索引擎得到,期間摻雜少許做者的私見,並會標明。 html5

大部份內容來自於http://www.infoq.com/minibooks/typescript-c-sharp-programmers java

你甚至能夠認爲這就是對這本英文小冊子的翻譯,實際上80%如此。 git

寫給那些已經有編程基礎,尤爲是掌握c語言、c#、java這一類型的靜態類型語言的同好。 程序員

鳴謝

先謝國家,雖然並不知道要謝些什麼。 github

感謝個人太太和個人貓,他們的陪伴讓我沉溺於電腦世界卻不孤獨。 web

感謝那些上班時間奮戰在QQ羣裏的程序鬥士們,他們讓我始終秉持一顆藝術家的心。 typescript

感謝微軟,TypeScript是微軟的註冊商標哦。 編程

真正的開篇文字

只要你是對html5這個話題感興趣的程序員,咱們就離不開JavaScript這個話題。而新興的TypeScript想必你也會有極大的興趣。JavaScript現在處處都是,web、服務器(經過NodeJS)、移動應用(經過各類框架),全部這些,TypeScript均可以使用,而且能夠爲JavaScript擴展出面向對象和靜態類型的特徵。 c#

TypeScript最初的靈感來自ECMAScript6,也就是將來的JavaScript。

TypeScript能讓咱們提早使用將來的語言特性,甚至更多,例如泛型這種語言特性。

TypeScript代碼,最終會編譯爲地道的JavaScript,兼容一切使用JavaScript的場合。

編譯過程主要是編譯時檢查,一點改寫,刪除類型批註和接口。刪除類型批註和接口這個過程稱爲類型擦除(Type Erasure)。

我從網上找到一張很好的圖片用來講明類型擦除,以下。

TypeScript的創造者是微軟的一個開發團隊,該團隊的領導者是C#之父 和 Delphi之父,Anders Hejlsberg。

2012年10月1日發佈,徹底開源。

當前版本已達1.8,已經擁有了不少生產力項目,TypeScript的主頁在http://www.typescriptlang.org/

咱們後面將詳細介紹TypeScript並對比他和其餘語言的異同,主要是C#。

關於TypeScript究竟是Compiling 仍是 Transpiling

這個話題很難說清楚,可是頗有必要在提到TypeScript的時候講一下,這兩個詞:編譯Compiling,Transpiling有人譯做轉譯,這是一個英文計算機術語。通常認爲轉譯是一種特殊的編譯,當將一種源代碼語言編譯成另一種源代碼語言時,就稱爲轉譯。

當編譯一個c#程序時,是由源代碼語言C#編譯爲IL,這就不能稱爲Transpiling,由於他們是徹底不一樣的東西。

而編譯TypeScript程序時,他變成了另一種源代碼JavaScript,這個就稱爲Transpiling(轉譯)。

但不管如何,Transpiling是Compiling的特例,Transpiling也屬於Compiling。

因此TypeScript轉譯爲Javascript,TypeScript編譯爲JavaScript,都是沒有問題的講法。

 

TypeScript語言特性

這裏快速介紹一下TypeScript的關鍵語法,好比顯示類型批註、類、接口。

雖然C# Java程序員都很熟悉面向對象,但TypeScript並不基於C#,因此仍是有所區別的。

TypeScript是靜態類型語言,須要編譯,擁有編譯時類型檢查的特性。

編譯時類型檢查可以確保類型安全,並方便開發更智能的自動完成功能,實際上TypeScript的各類開發工具都作得很不錯。

好比VisualStudio,編寫TypeScript文件時,就比編寫JavaScript要聰明的多。這就是靜態類型帶來的好處。

TypeScript文件

TypeScript文件的擴展名爲".ts",你可使用不少工具編寫.ts文件,好比visualstudio。更多信息,請看官網http://www.typescriptlang.org/

 

官網還提供了一個在線編寫測試.ts文件的環境http://www.typescriptlang.org/Playground/

一個TypeScript應用包含多個TypeScript代碼文件,一個代碼文件能夠包含多個ClassClass也能夠組成模塊。

模塊的概念和C#中組織類型的namespace比較接近。

運行時,TypeScript編譯獲得的JavaScript能夠經過Html標籤<Script>加入網頁中,也可使用其餘的模塊加載工具,好比NodeJS就內置了模塊加載工具。

不使用模塊組織依賴的時候,一個TypeScript文件依賴另外一個TypeScript文件,應該加上引用註釋

(這是可選的,通常也不使用命令行編譯,大部分圖形化工具不加也能夠)。

當使用模塊加載工具的時候(好比RequireJS,或者NodeJS內置加載工具),代碼以下:

不知道啥時RequireJS的同窗請自行補課。

 

當你使用import語句的時候,是有兩種模式的,CommonJS AMD模式,他們編譯爲JavaScript生成的代碼不一樣,這個根據你使用不一樣的加載工具請本身設置TypeScript編譯選項。

 

注:RequireJS使用CommonJS模式,NodeJS使用AMD模式。

 

類型

TypeScript的基本類型有 string,number,boolean,null 和undefined.

由於JavaScript沒有整數小數這些區分,因此TypeScript也沒有添加,統一使用number。

另外TypeScript添加了一個any類型,當須要動態類型時使用。這個與C#的動態關鍵字是相似的。

TypeScript支持數組類型,經過在類型後面添加方括號定義,好比string[].

也能夠自定義類型,在講到class的時候咱們細說。

類型推斷

當右側表達式足以肯定變量的類型時,TypeScript能夠自動肯定變量的類型,這個特性C#也有。

好比這個代碼

若是在VisualStudio中,鼠標懸停,依然能夠看到這三個變量被識別出來是各自不一樣的類型。

 

類型推斷還能處理更復雜的類型信息,好比這個代碼,無需類型標註便可得到靜態類型的好處。

寫完這個代碼之後,以後再鍵入example,再敲入.,也能夠得到自動完成提示,.name,.id.collection.

類型推斷始終是有侷限性的,基本上是依靠右側表達式來推斷。若是聲明變量時沒有推斷出來,過後賦值也推斷不出來了。

好比下面的代碼。

當聲明變量時沒法推斷出,變量即被標註爲 any 類型,any類型徹底沒有任何類型安全方面的保證。固然自動完成功能也沒有。

類型批註

TypeScript的類型是設計爲批註,而不是定義,是可選的,因此和C#的類型寫在前面不一樣,類型是以可選的形式寫在後面的。

咱們將上面的全部代碼都加上類型標註

這些標註的添加和上面自動類型推斷的結果是同樣的。可是閱讀代碼的人就能夠一眼看出。

模塊、類型、接口

TypeScript的模塊用於代碼組織,相似C#的namespace。一個模塊能夠包含多個類和接口。能夠將類和接口私有化或者導出,導出的意思就是公開,讓其餘模塊能夠訪問他們。

TypeScript的class和C#的class意義相同。實際上TypeScript的一個亮點就是他隱藏了JavaScript的原型設計,而是採用了更流行的基於類型的面向對象方式。你能夠擴展其餘的class,實現多個接口,添加構造函數,公開屬性和方法。這些都和c#的class很類似。

屬性和方法可使用public 或private訪問修飾符 修飾。當在構造函數的參數上使用訪問修飾符的時候,他們會自動爲該類型添加同名的屬性。請很是當心這個語法,這和不少語言都不一樣

如圖中Point的構造函數參數x,y 使用了public 訪問修飾符,因此會自動生成Point的成員變量x和y,這是TypeScript的特有語法。

圖中的export 關鍵字使類和接口在模塊外部可見。實現接口使用implements關鍵字,繼承類使用extends關鍵字,這點和C#直接用一個冒號表達不一樣。

當你擴展一個類時,用super關鍵字調用基類的方法。用this關鍵字來調用當前類的屬性和方法。重寫基類的方法是可選的。構造函數必需要調用基類的構造函數,編譯器會提醒你的。

模塊名稱包含點,一個模塊能夠定義在多個文件中。模塊的名字別太長,訪問的時候打字會比較累。下圖是一個比較累的例子

函數(或者叫功能)的參數

TypeScript的函數參數擁有豐富的特性:可選參數、默認參數、不定參數。

有一些和其餘語言的設計不太相同。下面將一一說明。

雖然在設計上,這些參數特性都不是必要的,可是TypeScript的這些地方都有些特殊性,你得了解一下,以備看懂。

可選參數的設計和C#基本一致,符號用? 表示可選參數,可選參數必須出如今必選參數以後。

默認參數只要在定義時給附上值就好了,而且和c#不一樣,TypeScript的默認參數不須要是常量,運行時可解釋便可,後文會有說明

下圖是特殊的默認參數

不定參數能夠指定任意數量,能夠爲零,這個設計也和c#相似,只是要添加三個點。

下面就是不定參數的一個典型使用場景

函數重載

Javascript是不容許重名函數的,TypeScript實現的重載和c#有很大的不一樣。

TypeScript的重載是要把全部的函數簽名寫出來,寫一份實現,而且最後一個函數簽名要能包含上面全部的函數簽名。

以下圖:

和C#三個重載的函數就擁有三個函數體不一樣,TypeScript的重載其實全是 overloadedMethod(input:any)這最後一個簽名的實現,上面的兩個只是兩個兼容的簽名。可是配合可選參數仍是可以表現出和c#的函數重載相似的調用方式。函數編寫方式免不了要寫不少的if了。

枚舉

TypeScript的枚舉很是相似C#,你能夠指定值。

也能夠反過來經過枚舉值取到枚舉的名字

這裏面的細節就再也不贅述了,你能夠觀察枚舉編譯爲JavaScript之後是什麼樣子

泛型

對c#程序員來講,TypeScript的泛型很熟悉,基本上是一致的設計。

類型約束

C#使用where關鍵字標記類型約束,TypeScript在尖括號內使用extends關鍵字,效果相同。

下面的例子中IExample約束了泛型必須是IMyInterface和他的派生類。

若是像下圖這樣用的話,就能約束爲同時繼承ClassOne和ClassTwo的類型。很費解吧,請特別注意

這是由於本質上TypeScript的類型系統並不那麼嚴格,下面的章節會詳細解釋TypeScript的類型系統

你也可使用泛型做爲泛型的類型約束,以下

結構類型

C#的類型系統是強制標記的,對象的類型必須顯示聲明。即便兩個類型擁有徹底相同的結構,他們也不是相同的類型。

TypeScript的類型系統是結構上的,建築結構,層次型的。結構相同的類型便可認爲是同一類型。

下面是C#中的一個例子

ClassA ClassB是徹底不一樣的類型,他們之間是不一樣的,必須顯示繼承接口才能讓他們兼容。

而在TypeScript中不是這樣,咱們用以下的例子來證實。ClassA ClassB ExampleC 擁有簽名一致的函數,因此他們就能夠兼容。

TypeScript的結構類型系統意味着你在c#中的觀念再也不成立,class name不是關鍵。這須要咱們寫代碼的時候時刻注意。

這玩意會讓代碼變幻無窮,若是你熟悉C#或者JAVA,這可能會讓你困惑。

 

看下面的例子,不須要class關鍵字,也會實實在在的產生類型。

在這個例子中,會產生一個匿名的類型

這個匿名的類型可讓開發工具提供自動完成功能,編譯器也會檢查。若是你嘗試將objA的name賦值一個數值,編譯器會檢查到告訴你錯誤。編譯器還會爲數組推斷類型。

訪問修飾器

TypeScript的訪問修飾器可能會給你一種弱小的感受,的確如此。他僅僅是一個編譯時功能。

模塊中的一切均爲私有,除非加上export關鍵字。沒有export關鍵字的類型僅能在模塊內實用。

類的內部,一切均爲公開,除非加上private 關鍵字。public只是爲了看起來意圖明確。

TypeScript的訪問修飾器就是這樣而已,沒有c#的 internal 和 protected這種修飾器,想要c#相似的功能就放棄吧。

TypeScript特性

內存管理

當你運行TypeScript 程序時,他會被編譯爲JavaScript程序來運行。JavaScript的內存管理和C#比較接近。內存在對象建立時分配,在對象再也不使用時回收。不一樣的是垃圾回收機制在JavaScript的世界裏沒有標準統一的實現,這意味着你的JavaScript程序的內存性能相比C#難以預測。

好比說,在比較早的瀏覽器上,可能使用的是引用計數垃圾回收機制,當一個對象的引用計數達到0時,將回收內存。這種垃圾回收機制比較快速和即時。可是當發生循環引用時,引用計數將永遠也沒法達到零。

比較新的瀏覽器使用標記與清掃垃圾回收機制來找出不可訪問到的對象,很大程度上避免了這個問題。這種垃圾回收機制比較緩慢,但他能避免循環引用致使的內存泄露。

關於兩種垃圾回收機制有不少的資料能夠研究,這裏只是想告訴你,別相信你的直覺,瀏覽器會很不一樣。

資源釋放

在TypeScript中,一般都不會使用到非託管的資源,Node.JS中多一點。大部分瀏覽器將底層交互API設計爲回調控制,不向你暴露對象,不須要你本身管理非託管資源。好比下面接近傳感器的API使用方法。

如你所見,使用回調並不須要管理任何引用。Node.js中有時會碰到須要本身釋放的對象,你要保證釋放這些對象,不然就會內存泄露。你可使用 try finally 塊,釋放代碼寫在 finally 塊中。這樣就能保證就算髮生任何錯誤,釋放代碼都會執行。

異常

在TypeScript中,你能夠用throw關鍵字引起一個異常。

在JavaScript中,throw能夠throw任何類型的東西。可是再TypeScript中,throw的必須是一個Error對象。

要自定義異常,能夠繼承Error類。當你須要一個特定的異常行爲或者你但願catch塊能夠分辨異常類型時,自定義異常就會頗有用。

處理異常須要使用try catch語句塊。大致上和c#的使用方法是很接近的,可是c#支持多個catch塊,TpyeScript不能夠,你能夠用error.name來區分異常類型。

若是須要一些即便發生異常也會調用的代碼,你就須要finally語句塊了,他們的執行順序以下圖

數組

TypeScript 從0.9開始,數組就是能夠指定內容的準確類型。用法是,用類型批註加上方括號。TypeScript會檢查加入到數組中的條目的類型,也會推斷從數組中檢索的條目的類型。

由於TypeScript沒有本身的框架庫,因此只能使用內置的JavaScript函數和瀏覽器接口,沒有像C#的List<T> 這樣的泛型庫。但這並不能阻止咱們本身創造一個。下面是一個泛型列表類的例子,只是個演示。

 

上面這個List類演示了許多TypeScript的語言特性和使用方法,就像C#的List<T>那樣。下面是如何使用這個List類的例子。

日期與時間

TypeScript中的Date對象是基於JavaScript Date 對象的,他是由從1970年零點 utc時間開始的毫秒數。

Date對象可以接受各類精度的初始化,以下。

你也可使用RFC和ISO格式的字符串初始化Date對象,固然,毫秒數也能夠(從1970年1月1日開始)。

請注意,這不是時間戳,時間戳單位是秒,數字比這個少幾個零。

Now

你能夠訪問如今的日期與時間,經過方法Date.Now();返回值是毫秒,你若是須要用Date對象去操做。須要用這個值去初始化一個Date對象

Date 的方法

當你有一個Date對象時,你能夠用內部方法獲取日期的一部分。有兩套方法,一套本地,一套UTC。在下面的實例中,你看到咱們把getUTCMonth的值加了1.由於返回值從零開始,因此一月是 02 月是 1,等等。

日期的各個部分爲年、月、日、小時、分鐘、秒、毫秒。全部這些值均可以在獲取本地的和 UTC 的。還能夠用 getDay getUTCDay獲得星期,從零開始,星期天爲 0,星期一爲1

 

也能夠利用各類格式顯示日期。以下。

事件

TypeScript中的事件是 DOM API(Document Object Model),DOM API事件是一套標準的鼠標和鍵盤交互和對象和窗體事件。下面的事件列表並不是詳盡無遺。

鼠標事件

事件

觸發時機

onblur

焦點離開目標組件

onclick

目標組件檢測到鼠標單擊

ondblclick

目標組件檢測到鼠標雙擊

onfocus

目標組件得到焦點

onmousedown

目標組件檢測到鼠標按下

onmousemove

目標組件檢測到鼠標指針移動

onmouseover

鼠標指針通過目標組件

onmouseout

鼠標指針離開目標組件

onmouseup

目標組件檢測到鼠標按鈕鬆開

 

鍵盤事件

事件

觸發時機

onkeydown

目標組件鍵盤按下

onkeypress

目標組件鍵盤按鍵按下並鬆開

onkeyup

目標組件鍵盤松開

對象事件

事件

觸發時機

onload

對象加載(文檔或圖像等)

onresize

對象尺寸改變

onscroll

一個文檔滾動

onunload

文檔關閉

表單事件

事件

觸發時機

onchange

目標輸入框的內容改變

onreset

表單重置(清空)

onsubmit

表單提交

自定義事件

TypeScript中自定義事件和DOM內置事件採用相同的機制發佈和偵聽。任何事件均可以有多個偵聽器和多個發佈者。下面是一個偵聽自定義事件的例子

 

下面的類發佈自定義的事件:

執行順序

事件按照他們被註冊的順序執行。這個因素很重要,由於事件處理程序是序列執行,不是同時,順序會影響邏輯。

當你註冊兩個事件偵聽器,而且第一個執行了5秒鐘。那麼第二個就不會執行,一直要等到第一個執行完畢以後纔會被執行。若是第一個偵聽器出錯,第二個仍是會執行。

你能夠用setTimeOut時間參數爲零的方式去執行你的長時間操做,這至關於多線程,就不會堵住其餘的事件執行了。

框架

TypeScript捆綁了那些經常使用對象和方法。由於Web標準在不斷的演變,你可能會常常發現一些新的東西尚未被包含在標準庫中。你能夠查看你計算機上的TypeScript標準庫文件,他在SDK目錄中,一般多是:

C:\Program Files (86) \Microsoft SDKs\TypeScript\lib.d.ts

你永遠也不該該修改這個文件,若是你須要新的定義,咱們能夠繼續增長新的定義文件。

下面的是 ClientRectList TypeScript庫文件中的當前定義。

若是要爲 ClientRectList添加一個新的isOrdered屬性,只需簡單的在你本身的程序中添加如下接口擴展程序,便可當即使用。

當它被添加到標準庫時,你本身的擴展會引起一個生成錯誤,到時把它刪除了就好了。

當你建立ClientRectList的實例時,你將可以訪問過去的方法,以及獲取新的 isOrdered 屬性。

除了這些TypeScript標準庫的定義,TypeScript沒有捆綁任何其餘的框架。在前一章中,咱們談到了,你能夠重建你的各類功能,好比像C#同樣,由於TypeScript有着豐富的語言功能。你也能夠訪問全部現有的 JavaScript 框架,jQueryKnockoutAngular和其餘數以百計的框架。可是他們都用純 JavaScript開發,你不會獲得加強的開發體驗,除非,你有一個匹配的定義文件。幸運的是,有一個項目,他們致力於爲全部的JavaScript框架提供TypeScript定義。Definitely Typed 項目,Github地址是:

https://github.com/borisyankov/DefinitelyTyped

建立定義

有時你會想使用JavaScript的庫、框架或者工具集。TypeScript編譯器難以理解這些外部的代碼,由於他們沒有類型信息。

動態定義

在程序中使用外部代碼的最簡單方法是聲明一個any變量。TypeScript編譯器容許any對象調用任何方法於屬性。這會讓你經過編譯,可是沒有自動完成和類型檢查。

在此示例中的特殊關鍵字是declare。這會告訴編譯器,這個變量是外部的,這個僅僅是編譯時的關鍵字,編譯爲JavaScript時會被擦除。

類型定義

爲了使用外部JS代碼能獲取更佳的開發體驗,你須要提供更全面的定義。能夠聲明變量、 模塊、 類和函數,定義外部代碼的類型信息。Declare關鍵字僅僅須要在定義的開頭使用一次。

 

若是但願外部代碼能夠由TypeScript擴展,定義爲class,不然,定義爲interface

這兩種定義方法的惟一區別是可否繼承擴展。這兩種狀況下,類型信息都僅爲編譯時使用,編譯爲JavaScript後都會進行類型擦除。

不少時候,定義會組成一系列接口,組合成很大的一幅圖景。你甚至能夠爲TypeScript不能實現的JavaScript方法建立定義。

例如,它是以下圖這樣作:

在此示例中有一個名爲move的難以想象的屬性,他能夠做爲函數使用。這樣一來,咱們就能夠聲明幾乎任何的JavaScript代碼, jQueryKnockoutAngularRequireJS 和其餘的老的JavaScript代碼,讓你能在TypeScript中使用它們而沒必要重寫。

一些有用的小技巧

獲取運行時類型

若是在運行時,想要獲得類的名稱,在C#中有反射這種方法,但TypeScript沒有明顯的內置方法。

靜態方法 getType,檢查編譯後的 JavaScript 函數,而後提取它的名字,這就是TypeScript中的類的名稱。

這種技術的限制是你不能得到包含類和模塊的完整名稱,這意味着:

MyModule.Example SomeOtherModule.Example 和沒包裝的叫作Example的類,它們全部的返回字符串均爲Example

 

擴展原生對象

TypeScript內置的定義文件描述了JavaScript原生對象和函數。你能夠在lib.d.ts庫文件中查看它們。你會注意到大部分都是使用interface定義的,不但願你繼承它們。但咱們仍是能夠擴展它們的。

例如,下面是給NodeList對象增長onclick事件。


可是這個代碼會被TypeScript編譯器警告,告訴你,NodeList對象沒有onclick函數。

爲了解決此爲題,你須要在你本身的代碼中添加定義代碼。

這個接口聲明能夠寫在任何引用的ts文件中。

 

相關文章
相關標籤/搜索