typescript 的接口只會關注值的外形,實際就是類型(條件)的檢查,只要知足就是被容許的。javascript
接口描述了類的公共部分。java
interface Person { firstName: string; lastName: string; } function greeter(person: Person) { return 'Hello, ' + person.firstName + ' ' + person.lastName; } var user = { firstName: 'Jane', lastName: 'User' }; document.body.innerHTML = greeter(user); // 可選屬性 interface SquareConfig { color?: string; width?: number; } function createSquare(config: SquareConfig): { color: string; area: number } { let newSquare = { color: 'white', area: 100 }; if ( config.width ) { newSquare.area = config.width * config.width; } return newSquare; } let mySquare = createSquare({color: 'black'}); // 只讀屬性(只能在對象剛剛建立的時候修改其值) interface Point { readonly x: number; readonly y: number; } let p1: Point = { x: 10, y: 20 }; p1.x = 5; // error // ReadonlyArray<T> 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 // 可使用斷言重寫 a = ro as number[]; // const vs readonly // 做爲變量則用 const // 做爲屬性則使用 readonly // 對於會額外帶有任意數量的其餘屬性,最佳方法是添加一個字符串索引簽名 // 一旦定義了任意屬性,那麼肯定屬性和可選屬性都必須是它的子屬性,以下代碼,即string、number爲any的子屬性 interface SquareConfig { color?: string; width?: number; [propName: string]: any; // 字符串索引簽名 }
interface SearchFunc { // 定義調用簽名 (source: string, subString: string): boolean; } let mySearch: SearchFunc; mySearch = function(source: string, subString: string) { let result = source.search(subString); if ( result == -1 ) { return false; } else { return true; } } // 對於函數類型的類型檢查,函數的參數名不須要與接口定義的名字相匹配,可是要求對應位置上的參數類型是兼容的。
// 當用 number 去索引 StringArray 時會獲得 string 類型的返回值 interface StringArray { [index: number]: string; } let myArray: StringArray; myArray = ['Bob', 'Fred']; let myStr: string = myArray[0]; // 防止給索引賦值 interface ReadonlyStringArray { readonly [index: number]: string; } let myArray: ReadonlyStringArray = ['Alice', 'Bob']; myArray[2] = 'Mallory'; // error // 確保全部屬性與其返回值類型相匹配 interface NumberDictionary { [index: string]: number; length: number; name: string; // 錯誤,name的類型不是索引類型的子類型 }
// 強制一個類去符合某種契約 interface ClockInterface { currentTime: Date; } class Clock implements ClockInterface { currentTime: Date; constructor(h: number, m: number) { } } // 在接口中描述一個方法,在類中實現它 interface ClockInterface { currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } } // 類靜態部分與實例部分的區別 interface ClockConstructor { new (hour: number, minute: number): ClockInterface; } interface ClockInterface { tick(); } function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface { return new cotr(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);
和類同樣,接口也能夠相互擴展。可以從一個接口裏複製成員到另外一個接口裏,更靈活地將接口分割到可重用的模塊裏。git
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;
// 一個對象能夠同時作爲函數和對象使用,並帶有額外的屬性 interface Counter { (start: number): string; interval: number; reset(): void; } function getCounter(): Counter { let counter = <Counter>function (start: number) { }; counter.interval = 123; counter.reset = function() { }; return counter; } let c = getCounter(); c(10); c.reset(); c.interval = 5.0;
當接口繼承類類型時,它會繼承類的成員但不包括其實現。接口一樣會繼承到類的private和protected成員。意味着這個接口只能被這個類或其子類所實現。typescript
class Control { private state: any; } interface SelectableControl extends Control { select(): void; } class Button extends Control { select() { } } class TextBox extends Control { select() { } } class Image { select() { } } class Location { select() { } }