1. 程式人生 > >第五章 接口

第五章 接口

select() int source ict 類型 cati time 5.0 聲明

接口

一、介紹

  • TypeScript 的核心原則之一是對值所具有的結構進行類型檢查。 它有時被稱做“鴨式辨型法”或“結構性子類型化”。 在 TypeScript 裏,接口的作用就是為這些類型命名和為你的代碼或第三方代碼定義契約

二、接口初探

interface LabelledValue {
    label: string;
}

function printLabel(labelledObj: LabelledValue) {
    console.log(labelledObj.label);
}

let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);

三、可選屬性

interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
    let newSquare = { color: "white", area: 100 };
    if (config.color) {
        newSquare.color = config.color;
    }
    if (config.width) {
        newSquare.area = config.width * config.width;
    }
    return newSquare;
}

let mySquare = createSquare({ color: "black" });

四、只讀屬性

  • readonly
interface Point {
    readonly x: number;
    readonly y: number;
}
  • ReadonlyArray類型
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!
  • readonly vs const
  • 最簡單判斷該用 readonly 還是 const 的方法:是看要把它做為變量使用還是做為一個屬性。 做為變量使用的話用 const,若做為屬性則使用 readonly。

五、額外的屬性檢查

interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
    // ...
}

// error: 'colour' not expected in type 'SquareConfig'
let mySquare = createSquare({ colour: "red", width: 100 });

六、函數類型

  • 接口能夠描述 JavaScript 中對象擁有的各種各樣的外形。 除了描述帶有屬性的普通對象外,接口也可以描述函數類型。

  • 為了使用接口表示函數類型,我們需要給接口定義一個調用簽名。 它就像是一個只有參數列表和返回值類型的函數定義。參數列表裏的每個參數都需要名字和類型。

//使用接口表示函數類型
interface SearchFunc {
    (source: string, subString: string): boolean;
}

//使用這個函數類型的接口,創建一個函數類型的變量,並將一個同類型的函數賦值給這個變量
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    let result = source.search(subString);
    return result > -1;
};

七、可索引的類型

  • 與使用接口描述函數類型差不多,我們也可以描述那些能夠“通過索引得到”的類型,比如 a[10]或 ageMap["daniel"]。 可索引類型具有一個 索引簽名,它描述了對象索引的類型,還有相應的索引返回值類型。
interface StringArray {
    [index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];

//字符串索引簽名能夠很好的描述dictionary模式,並且它們也會確保所有屬性與其返回值類型相匹配。
interface NumberDictionary {
    [index: string]: number;
    length: number; // 可以,length是number類型
    name: string; // 錯誤,`name`的類型與索引類型返回值的類型不匹配
}

//你可以將索引簽名設置為只讀,這樣就防止了給索引賦值
interface ReadonlyStringArray {
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!

八、類類型

  • 實現接口
//與C#或Java裏接口的基本作用一樣,TypeScript也能夠用它來明確的強制一個類去符合某種契約。
interface ClockInterface {
    currentTime: Date;
}

class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number) {}
}

//你也可以在接口中描述一個方法,在類裏實現它,如同下面的setTime方法一樣
interface ClockInterface {
    currentTime: Date;
    setTime(d: Date);
}

class Clock implements ClockInterface {
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) {}
}
//PS:接口描述了類的公共部分,而不是公共和私有兩部分。 它不會幫你檢查類是否具有某些私有成員

九、繼承接口

//和類一樣,接口也可以相互繼承
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 成員。 這意味著當你創建了一個接口繼承了一個擁有私有或受保護的成員的類時,這個接口類型只能被這個類或其子類所實現(implement)
class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() {}
}

class TextBox extends Control {}

// 錯誤:“Image”類型缺少“state”屬性。
class Image implements SelectableControl {
    select() {}
}

class Location {}

第五章 接口