做爲TypeScript中的核心特點之一,可以讓類型檢查幫助咱們知道一個對象應該有什麼,相比咱們在編寫JavaScript的時候常常遇到函數須要傳遞參數,可能在編寫的時候知道這個對象可以提供哪些值,可是之後維護的時候負責看這段代碼的人都沒法確認這個對象還有其餘的哪些值,就須要翻閱源碼看看調用這個函數的代碼。java
在開始正題以前咱們先來一個簡單的例子。後端
--TypeScript數組
1 function printLabel(labelObject: { label: string }) { 2 console.log(labelObject.label); 3 } 4 5 var myobj = { size: 10, label: "Size 10 Object" }; 6 printLabel(myobj);
--JavaScript前後端分離
function printLabel(labelObject) { console.log(labelObject.label); } var myobj = { size: 10, label: "Size 10 Object" }; printLabel(myobj);
類型檢查會在咱們調用printLabel的時候檢查傳進去的參數,確保該參數中存在一個名字爲label而且類型爲string的屬性,固然咱們能夠看到這個參數的值遠遠比咱們函數要求的多,但這並不會形成影響,經過最終的源碼咱們也能夠看到最終生成的js代碼並無比原來多出多少,可是卻可以爲咱們提供強大的類型檢查。ide
下面咱們能夠引入正題了,咱們將使用接口的方式實現上面的例子。函數
--TypeScript網站
1 interface LabelledValue { 2 label: string 3 } 4 5 function printLabel(labelObject: LabelledValue) { 6 console.log(labelObject.label); 7 } 8 9 var myobj = { size: 10, label: "Size 10 Object" }; 10 printLabel(myobj);
--JavaScriptthis
同上spa
這裏咱們看到若是利用接口可以更便於管理,更主要的是接口中除了能夠定義屬性也能夠定義函數等,對於中大型項目,特別是先後端分離的網站來講對於之後的維護和迭代能顧節省時間成本並提升質量。prototype
可是因爲歷史緣由,TypeScript並不能孤立存在,仍是須要兼容其餘庫,那麼就致使咱們的接口還要考慮另外一種狀況就是可選值,好比下面這個例子。
--TypeScript
1 interface SquareConfig { 2 color?: string; 3 width?: number; 4 } 5 6 function createSquare(config: SquareConfig): { color: string; area: number } { 7 var newsquare = { color: "white", area: 100 }; 8 if (config.color) { 9 newsquare.color = config.color; 10 } 11 if (config.width) { 12 newsquare.area = config.width * config.width; 13 } 14 return newsquare; 15 } 16 17 var mySquare = createSquare({ color: "black" });
--JavaScript
1 function createSquare(config) { 2 var newsquare = { color: "white", area: 100 }; 3 if (config.color) { 4 newsquare.color = config.color; 5 } 6 if (config.width) { 7 newsquare.area = config.width * config.width; 8 } 9 return newsquare; 10 } 11 12 var mySquare = createSquare({ color: "black" });
經過接口咱們知道可選屬性就是在屬性名稱的後面加上問號就能夠了,可是開發的時候要注意就是要經過if判斷下該值是否存在。
玩轉了屬性,下面咱們開始在接口中放入函數,下面咱們先放一個函數。
--TypeScript
1 interface SearchFunc { 2 (source: string, substring: string): boolean; 3 } 4 5 var mySearch: SearchFunc; 6 mySearch = function (source: string, substring: string) { 7 var result = source.search(substring); 8 if (result == -1) { 9 return false; 10 } else { 11 return true; 12 } 13 };
--JavaScript
var mySearch; mySearch = function (source, substring) { var result = source.search(substring); if (result == -1) { return false; } else { return true; } };
你們確定會很奇怪,下面爲何定義了這個接口的變量可是賦的確是一個函數,若是你們有C#和java語言的基礎會發現SearchFunc中的函數是沒有函數名的,因此mySearch的類型就是一個函數,只是會進行類型檢查,你是不能賦其餘函數簽名不同的函數給他的。
接口除了能夠描述函數類型也能夠描述數組類型,數組類型擁有一個「index」類型,是用來索引數組的,利用這個咱們就能夠實現除了數組之外還可以實現字典類型。
--TypeScript
1 interface StringArray { 2 [index: number]: string; 3 } 4 5 var myArray: StringArray; 6 myArray = ["Bob", "Fred"];
--JavaScript
1 var myArray; 2 myArray = ["Bob", "Fred"];
Index類型可以支持兩種類型:string和number,因此咱們可以實現字典類型,好比下面這種類型。
--TypeScript
1 interface StringArray { 2 [index: string]: string; 3 } 4 5 var myArray: StringArray; 6 myArray = { 7 "dede": "dede", 8 "ete":"dede" 9 };
--JavaScript
1 var myArray; 2 myArray = { 3 "dede": "dede", 4 "ete": "dede" 5 };
像C#和Java語言中同樣,接口最基礎的做用就是讓類去實現接口,因此這也是TypeScript語言的特色之一。好比下面的例子咱們將實現一個帶有一個屬性的接口。
--TypeScript
1 interface ClockInterface { 2 currentTime: Date 3 } 4 5 class Clock implements ClockInterface { 6 currentTime: Date; 7 constructor(h: number, m: number) { } 8 }
--JavaScript
1 var Clock = (function () { 2 function Clock(h, m) { 3 } 4 return Clock; 5 })();
這裏咱們能夠看到最終的JS中並無將currentTime做爲變量加入到this中,由於在這個類中咱們並無使用到這個值,因此這個變量只會在咱們正式的使用的時候添加到這個類中,若是不用這個類就等同於沒有這個變量。
上面咱們僅僅只是在接口中寫了一個屬性,下面咱們在接口中增長一個方法。
--TypeScript
1 interface ClockInterface { 2 currentTime: Date; 3 setTime(d: Date); 4 } 5 6 class Clock implements ClockInterface { 7 currentTime: Date; 8 setTime(d: Date) { 9 this.currentTime = d; 10 } 11 constructor(h: number, m: number) { } 12 }
--JavaScript
1 var Clock = (function () { 2 function Clock(h, m) { 3 } 4 Clock.prototype.setTime = function (d) { 5 this.currentTime = d; 6 }; 7 return Clock; 8 })();
當咱們使用類和接口,須要知道類是存在靜態和實例的,這也就意味着若是你的接口若是存在構造方法而且須要一個類去實現,那麼你將會看到錯誤信息,好比下面這段。
--TypeScript
1 interface ClockInterface { 2 new (hour: number, minute: number); 3 } 4 5 class Clock implements ClockInterface { 6 currentTime: Date; 7 constructor(h: number, m: number) { } 8 }
這是由於當一個類實現一個接口的時候只有實例部分是被容許的,而構造方法偏偏屬於靜態,並不包含在內。
固然含有構造方法的接口是有其用途的,好比下面這樣的用法。
--TypeScript
1 interface ClockInterface { 2 new (hour: number, minute: number); 3 } 4 5 class Clock { 6 currentTime: Date; 7 constructor(h: number, m: number) { } 8 } 9 10 var cs: ClockInterface = Clock; 11 var newClock = new cs(2, 3);
--JavaScript
1 var Clock = (function () { 2 function Clock(h, m) { 3 } 4 return Clock; 5 })(); 6 7 var cs = Clock; 8 var newClock = new cs(2, 3);
這個特性跟類能夠繼承其餘類同樣,接口也能夠擴展其餘的接口,這將會致使被繼承的接口中的全部的內容都會被複制到另外一個接口中。下面咱們來看一個簡單的例子。
--TypeScript
1 interface Shape { 2 color: string; 3 } 4 5 interface Square extends Shape { 6 sideLength: number; 7 } 8 9 var square = <Square>{}; 10 square.color = "blue"; 11 square.sideLength = 10;
--JavaScript
1 var square = {}; 2 square.color = "blue"; 3 square.sideLength = 10;
一個接口不只僅只能擴展一個接口,是能夠擴展多個接口的。好比下面這樣。
--TypeScript
1 interface Shape { 2 color: string; 3 } 4 5 interface PenStroke { 6 penWidth: number; 7 } 8 9 interface Square extends Shape, PenStroke { 10 sideLength: number; 11 } 12 13 var square = <Square>{}; 14 square.color = "blue"; 15 square.sideLength = 10; 16 square.penWidth = 5.0;
--JavaScript
1 var square = {}; 2 square.color = "blue"; 3 square.sideLength = 10; 4 square.penWidth = 5.0;
咱們再次以前提到過,接口能夠描述不少真實世界中JavaScript的類型,由於JavaScript的動態和天生的靈活性,你或許會遇到一些須要多種複合的類型。
好比下面的實例,這個對象將扮演着函數和一個對象。
--TypeScript
1 interface Counter { 2 (start: number): string; 3 interval: number; 4 reset(): void; 5 } 6 7 var c: Counter; 8 c(10); 9 c.reset(); 10 c.interval = 5.0;
--JavaScript
1 var c; 2 c(10); 3 c.reset(); 4 c.interval = 5.0;
對於須要使用第三方JavaScript庫的狀況下,咱們就會須要使用到上面介紹的知識。固然如今不少經常使用的JavaScript庫都已經存在了,咱們能夠經過nuget獲取到。