TypeScript 中接口詳解
在 TypeScript 中,接口是用作約束作用的,在編譯成 JavaScript 的時候,所有的接口都會被擦除掉,因為 JavaScript 中并沒有接口這一概念。
先看看一個簡單的例子:
function printLabel(labelledObj: { label: string }) {
console.log(labelledObj.label);
}
var myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);
那么在該方法中,labelledObj 的類型就是 {label: string},看上去可能有點(diǎn)復(fù)雜,但我們看見看看下面 myObj 的聲明就知道,這是聲明了一個擁有 size 屬性(值為 10)和 label 屬性(值為 "Size 10 Object")的對象。所以方法參數(shù) labelledObj 的類型是 {label: string} 即表明參數(shù)擁有一個 string 類型的 label 屬性。
但是,這么寫的話,這個方法看上去還是有點(diǎn)讓人糊涂。那么就可以用接口(interface)來定義這個方法的參數(shù)類型。
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
var myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);
可選屬性
有些時候,我們并不需要屬性一定存在,就可以使用可選屬性這一特性來定義。
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" });
那么我們就傳入了實(shí)現(xiàn)一個 SquareConfig 接口的對象入 createSquare 方法。
既然完全是可有可無的,那么為什么還要定義呢?對比起完全不定義,定義可選屬性有兩個優(yōu)點(diǎn)。1、如果存在屬性,能約束類型,這是十分關(guān)鍵的;2、能得到語法智能提示,假如誤將方法體中 color 寫成 collor,那么編譯是不通過的。
方法類型
在 JavaScript 中,方法 function 是一種基本類型。在面向?qū)ο笏枷胫?,接口的?shí)現(xiàn)是靠類來完成的,而 function 作為一種類型,是不是能夠?qū)崿F(xiàn)接口呢?答案是肯定的。
在 TypeScript 中,我們可以使用接口來約束方法的簽名。
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;
}
}
上面代碼中,我們定義了一個接口,接口內(nèi)約束了一個方法的簽名,這個方法有兩個字符串參數(shù),返回布爾值。在第二段代碼中我們聲明了這個接口的實(shí)現(xiàn)。
需要注意的是,編譯器僅僅檢查類型是否正確(參數(shù)類型、返回值類型),因此參數(shù)的名字我們可以換成別的。
var mySearch: SearchFunc;
mySearch = function(src: string, sub: string) {
var result = src.search(sub);
if (result == -1) {
return false;
}
else {
return true;
}
}
這樣也是能夠編譯通過的。
數(shù)組類型
在上面我們在接口中定義了方法類型,那么,數(shù)組類型又應(yīng)該如何定義呢?很簡單。
interface StringArray {
[index: number]: string;
}
var myArray: StringArray;
myArray = ["Bob", "Fred"];
那么 myArray 就是一個數(shù)組,并且索引器是 number 類型,元素是 string。
在接口的定義里面,索引器的名字一般為 index(當(dāng)然也可以改成別的,但一般情況下都是保持名字為 index)。所以改成
interface StringArray {
[myIndex: number]: string;
}
var myArray: StringArray;
myArray = ["Bob", "Fred"];
也是 ok 的。
需要注意的是,索引器的類型只能為 number 或者 string。
interface Array{
[index: number]: any;
}
interface Dictionary{
[index: string]: any;
}
上面兩段都是可以編譯通過的。
最后還有一點(diǎn)要注意的是,如果接口已經(jīng)是數(shù)組類型的話,接口中定義的其它屬性的類型都必須是該數(shù)組的元素類型。例如:
interface Dictionary {
[index: string]: string;
length: number; // error, the type of 'length' is not a subtype of the indexer
}
那么將無法編譯通過,需要將 length 改成 string 類型才可以。
使用類實(shí)現(xiàn)接口
一般情況下,我們還是習(xí)慣使用一個類,實(shí)現(xiàn)需要的接口,而不是像上面直接用接口。
interface ClockInterface {
currentTime: Date;
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number) { }
}
在 TypeScript 中,使用 class 關(guān)鍵字來聲明了,這跟 EcmaScript 6 是一樣的。
另外,我們可以使用接口來約束類中定義的方法。
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
在 TypeScript 中,我們可以為接口定義構(gòu)造函數(shù)。
interface ClockInterface {
new (hour: number, minute: number);
}
接下來天真的我們可能會接著這么寫:
interface ClockInterface {
new (hour: number, minute: number);
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number) { }
}
這是不行的?。?!因為構(gòu)造函數(shù)是 static(靜態(tài))的,而類僅能夠?qū)崿F(xiàn)接口中的 instance(實(shí)例)部分。
那么這個接口中定義的構(gòu)造函數(shù)豈不是沒作用?既然 TypeScript 提供了這項功能,那么肯定不會是沒作用的。聲明的方法比較特殊:
interface ClockStatic {
new (hour: number, minute: number);
}
class Clock {
currentTime: Date;
constructor(h: number, m: number) { }
}
var cs: ClockStatic = Clock;
var newClock = new cs(7, 30);
正常情況下我們是寫 new Clock 的,這里就將 Clock 類指向了 ClockStatic 接口。需要注意的是,newClock 變量的類型是 any。
繼承接口
像類一樣,接口也能實(shí)現(xiàn)繼承,使用的是 extends 關(guān)鍵字。
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
var square = <Square>{};
square.color = "blue";
square.sideLength = 10;
當(dāng)然也能繼承多個接口。
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
var square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
需要注意的是,盡管支持繼承多個接口,但是如果繼承的接口中,定義的同名屬性的類型不同的話,是不能編譯通過的。
interface Shape {
color: string;
test: number;
}
interface PenStroke {
penWidth: number;
test: string;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
那么這段代碼就無法編譯通過了,因為 test 屬性的類型無法確定。
同時使用上面所述的類型
如果僅能單一使用某種類型,那么這接口也未免太弱了。但幸運(yùn)的是,我們的接口很強(qiáng)大。
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
var c: Counter;
c(10);
c.reset();
c.interval = 5.0;
這樣就使用到三種類型了,分別是方法(接口自己是個方法)、屬性、方法(定義了方法成員)。
以上所述就是本文的全部內(nèi)容了,希望大家能夠喜歡。
相關(guān)文章
獲取服務(wù)器傳來的數(shù)據(jù) 用JS去空格的正則表達(dá)式
獲取服務(wù)器傳來的數(shù)據(jù) 用JS去空格的正則表達(dá)式,需要的朋友可以參考下2012-03-03
一篇文章弄懂javascript中的執(zhí)行棧與執(zhí)行上下文
這篇文章主要給大家介紹了關(guān)于javascript中執(zhí)行棧與執(zhí)行上下文的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用javascript具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
微信小程序picker組件關(guān)于objectArray數(shù)據(jù)類型的綁定方法
這篇文章主要介紹了微信小程序picker組件關(guān)于objectArray數(shù)據(jù)類型的綁定方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03
js當(dāng)一個變量為函數(shù)時 應(yīng)該注意的一點(diǎn)細(xì)節(jié)小結(jié)
變量testFun為一個匿名函數(shù),匿名函數(shù)返回的一個testFun.init對象(也是一個匿名函數(shù))2011-12-12

