萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> TypeScript 中接口詳解

TypeScript 中接口詳解

   TypeScript核心設計原則之一就是類型檢查,通過使用接口(Interfaces)可以進行類型檢查,滿足傳統面向對象思想,利於有效開發,有效避免類型轉換問題。

  在 TypeScript 中,接口是用作約束作用的,在編譯成 JavaScript 的時候,所有的接口都會被擦除掉,因為 JavaScript 中並沒有接口這一概念。

  先看看一個簡單的例子:

  ?

1 2 3 4 5 6 function printLabel(labelledObj: { label: string }) { console.log(labelledObj.label); }   var myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);

  那麼在該方法中,labelledObj 的類型就是 {label: string},看上去可能有點復雜,但我們看見看看下面 myObj 的聲明就知道,這是聲明了一個擁有 size 屬性(值為 10)和 label 屬性(值為 "Size 10 Object")的對象。所以方法參數 labelledObj 的類型是 {label: string} 即表明參數擁有一個 string 類型的 label 屬性。

  但是,這麼寫的話,這個方法看上去還是有點讓人糊塗。那麼就可以用接口(interface)來定義這個方法的參數類型。

  ?

1 2 3 4 5 6 7 8 9 10 interface LabelledValue { label: string; }   function printLabel(labelledObj: LabelledValue) { console.log(labelledObj.label); }   var myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);

  可選屬性

  有些時候,我們並不需要屬性一定存在,就可以使用可選屬性這一特性來定義。

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface SquareConfig { color?: string; width?: number; }   function createSquare(config: SquareConfig): { color: string; area: number } { var newSquare = { color: "white", area: 100 }; if (config.color) { newSquare.color = config.color; } if (config.width) { newSquare.area = config.width * config.width; } return newSquare; }   var mySquare = createSquare({ color: "black" });

  那麼我們就傳入了實現一個 SquareConfig 接口的對象入 createSquare 方法。

  既然完全是可有可無的,那麼為什麼還要定義呢?對比起完全不定義,定義可選屬性有兩個優點。1、如果存在屬性,能約束類型,這是十分關鍵的;2、能得到語法智能提示,假如誤將方法體中 color 寫成 collor,那麼編譯是不通過的。

  方法類型

  在 JavaScript 中,方法 function 是一種基本類型。在面向對象思想中,接口的實現是靠類來完成的,而 function 作為一種類型,是不是能夠實現接口呢?答案是肯定的。

  在 TypeScript 中,我們可以使用接口來約束方法的簽名。

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 interface SearchFunc { (source: string, subString: string): boolean; }   var mySearch: SearchFunc; mySearch = function(source: string, subString: string) { var result = source.search(subString); if (result == -1) { return false; } else { return true; } }

  上面代碼中,我們定義了一個接口,接口內約束了一個方法的簽名,這個方法有兩個字符串參數,返回布爾值。在第二段代碼中我們聲明了這個接口的實現。

  需要注意的是,編譯器僅僅檢查類型是否正確(參數類型、返回值類型),因此參數的名字我們可以換成別的。

  ?

1 2 3 4 5 6 7 8 9 10 var mySearch: SearchFunc; mySearch = function(src: string, sub: string) { var result = src.search(sub); if (result == -1) { return false; } else { return true; } }

  這樣也是能夠編譯通過的。

  數組類型

  在上面我們在接口中定義了方法類型,那麼,數組類型又應該如何定義呢?很簡單。

  ?

1 2 3 4 5 6 interface StringArray { [index: number]: string; }   var myArray: StringArray; myArray = ["Bob", "Fred"];

  那麼 myArray 就是一個數組,並且索引器是 number 類型,元素是 string。

  在接口的定義裡面,索引器的名字一般為 index(當然也可以改成別的,但一般情況下都是保持名字為 index)。所以改成

  ?

1 2 3 4 5 6 interface StringArray { [myIndex: number]: string; }   var myArray: StringArray; myArray = ["Bob", "Fred"];

  也是 ok 的。

  需要注意的是,索引器的類型只能為 number 或者 string。

  ?

1 2 3 4 5 6 7 interface Array{ [index: number]: any; }   interface Dictionary{ [index: string]: any; }

  上面兩段都是可以編譯通過的。

  最後還有一點要注意的是,如果接口已經是數組類型的話,接口中定義的其它屬性的類型都必須是該數組的元素類型。例如:

  ?

1 2 3 4 interface Dictionary { [index: string]: string; length: number; // error, the type of 'length' is not a subtype of the indexer }

  那麼將無法編譯通過,需要將 length 改成 string 類型才可以。

  使用類實現接口

  一般情況下,我們還是習慣使用一個類,實現需要的接口,而不是像上面直接用接口。

  ?

1 2 3 4 5 6 7 8 interface ClockInterface { currentTime: Date; }   class Clo
copyright © 萬盛學電腦網 all rights reserved