Typescript 接口(interface)

概述

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() { }
}
相關文章
相關標籤/搜索