接口
介紹
TypeScript 的核心原則之一是對(duì)值所具有的結(jié)構(gòu)進(jìn)行類型檢查。 它有時(shí)被稱做“鴨式辨型法”或“結(jié)構(gòu)性子類型化”次询。 在 TypeScript 里,接口的作用就是為這些類型命名和為你的代碼或第三方代碼定義契約
可選屬性
帶有可選屬性的接口與普通的接口定義差不多栖袋,只是在可選屬性名字定義的后面加一個(gè) 符號(hào)叹卷。
interface SquareConfig {
color?: string;
width?: number;
}
只讀屬性
一些對(duì)象屬性只能在對(duì)象剛剛創(chuàng)建的時(shí)候修改其值。 你可以在屬性名前用 來指定只讀屬性:
interface Point {
readonly x: number;
readonly y: number;
}
TypeScript 具有 類型绅作,它與 Array<T>相似芦圾,只是把所有可變方法去掉了,因此可以確保數(shù)組創(chuàng)建后再也不能被修改:
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
額外的屬性檢查
添加一個(gè)字符串索引簽名, 前提是你能夠確定這個(gè)對(duì)象可能具有某些做為特殊用途使用的額外屬性
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any;
}
函數(shù)類型
接口能夠描述 JavaScript 中對(duì)象擁有的各種各樣的外形俄认。 除了描述帶有屬性的普通對(duì)象外个少,接口也可以描述函數(shù)類型。
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function (src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
};
可索引的類型
與使用接口描述函數(shù)類型差不多眯杏,我們也可以描述那些能夠“通過索引得到”的類型夜焦,比如 a[10]或 ageMap["daniel"]。 可索引類型具有一個(gè) 索引簽名岂贩,它描述了對(duì)象索引的類型茫经,還有相應(yīng)的索引返回值類型。
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
TypeScript 支持兩種索引簽名:字符串和數(shù)字萎津。 可以同時(shí)使用兩種類型的索引卸伞,但是數(shù)字索引的返回值必須是字符串索引返回值類型的子類型。
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}
// 錯(cuò)誤:使用數(shù)值型的字符串索引锉屈,有時(shí)會(huì)得到完全不同的Animal!
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog;
}
類類型
實(shí)現(xiàn)接口
與 C#或 Java 里接口的基本作用一樣荤傲,TypeScript 也能夠用它來明確的強(qiáng)制一個(gè)類去符合某種契約
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) {}
}
接口描述了類的公共部分,而不是公共和私有兩部分部念。 它不會(huì)幫你檢查類是否具有某些私有成員弃酌。
類靜態(tài)部分與實(shí)例部分的區(qū)別
當(dāng)你操作類和接口的時(shí)候氨菇,你要知道類是具有兩個(gè)類型的:靜態(tài)部分的類型和實(shí)例的類型。 你會(huì)注意到妓湘,當(dāng)你用構(gòu)造器簽名去定義一個(gè)接口并試圖定義一個(gè)類去實(shí)現(xiàn)這個(gè)接口時(shí)會(huì)得到一個(gè)錯(cuò)誤:
interface ClockConstructor {
new (hour: number, minute: number);
}
//類“Clock”錯(cuò)誤實(shí)現(xiàn)接口“ClockConstructor”查蓉。
class Clock implements ClockConstructor {
currentTime: Date;
constructor(h: number, m: number) {}
}
這里因?yàn)楫?dāng)一個(gè)類實(shí)現(xiàn)了一個(gè)接口時(shí),只對(duì)其實(shí)例部分進(jìn)行類型檢查榜贴。 constructor 存在于類的靜態(tài)部分豌研,所以不在檢查的范圍內(nèi)。
因此唬党,我們應(yīng)該直接操作類的靜態(tài)部分鹃共。 看下面的例子,我們定義了兩個(gè)接口驶拱, ClockConstructor 為構(gòu)造函數(shù)所用和 ClockInterface 為實(shí)例方法所用霜浴。 為了方便我們定義一個(gè)構(gòu)造函數(shù) createClock,它用傳入的類型創(chuàng)建實(shí)例蓝纲。
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick();
}
function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
return new ctor(hour, minute);
}
class DigitalClock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log("beep beep");
}
}
class AnalogClock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log("tick tock");
}
}
let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);
繼承接口
單繼承
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
多繼承
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
接口繼承類
當(dāng)接口繼承了一個(gè)類類型時(shí)阴孟,它會(huì)繼承類的成員但不包括其實(shí)現(xiàn)。 就好像接口聲明了所有類中存在的成員税迷,但并沒有提供具體實(shí)現(xiàn)一樣永丝。 接口同樣會(huì)繼承到類的 private 和 protected 成員。 這意味著當(dāng)你創(chuàng)建了一個(gè)接口繼承了一個(gè)擁有私有或受保護(hù)的成員的類時(shí)箭养,這個(gè)接口類型只能被這個(gè)類或其子類所實(shí)現(xiàn)(implement)慕嚷。
當(dāng)你有一個(gè)龐大的繼承結(jié)構(gòu)時(shí)這很有用,但要指出的是你的代碼只在子類擁有特定屬性時(shí)起作用毕泌。 這個(gè)子類除了繼承至基類外與基類沒有任何關(guān)系喝检。 例:
class Control {
private state: any;
}
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control implements SelectableControl {
select() {}
}
class TextBox extends Control {
select() {}
}
// 錯(cuò)誤:“Image”類型缺少“state”屬性。
class Image implements SelectableControl {
select() {}
}
class Location {}