1. 程式人生 > >TypeScript基礎入門之宣告合併(三)

TypeScript基礎入門之宣告合併(三)

宣告合併

將名稱空間與類,函式和列舉合併

名稱空間足夠靈活,也可以與其他型別的宣告合併。 為此,名稱空間宣告必須遵循它將與之合併的宣告。 生成的宣告具有兩種宣告型別的屬性。 TypeScript使用此功能來模擬JavaScript以及其他程式語言中的某些模式。

將名稱空間與類合併

這為使用者提供了一種描述內部類的方法。

class Album {
    label: Album.AlbumLabel;
}

namespace Album {
    export class AlbumLabel { }
}

合併成員的可見性規則與"合併名稱空間"部分中描述的相同,因此我們必須匯出合併類的AlbumLabel類才能看到它。 最終結果是在另一個類內部管理的類。 您還可以使用名稱空間向現有類新增更多靜態成員。

除了內部類的模式之外,您還可能熟悉建立函式的JavaScript實踐,然後通過向函式新增屬性來進一步擴充套件函式。 TypeScript使用宣告合併以型別安全的方式構建這樣的定義。

function buildLabel(name: string): string {
    return buildLabel.prefix + name + buildLabel.suffix;
}

namespace buildLabel {
    export let suffix = "";
    export let prefix = "Hello, ";
}

console.log(buildLabel("Sam Smith"));

同樣,名稱空間可用於擴充套件具有靜態成員的列舉:

enum Color {
    red = 1,
    green = 2,
    blue = 4
}

namespace Color {
    export function mixColor(colorName: string) {
        if (colorName == "yellow") {
            return Color.red + Color.green;
        }
        else if (colorName == "white") {
            return Color.red + Color.green + Color.blue;
        }
        else if (colorName == "magenta") {
            return Color.red + Color.blue;
        }
        else if (colorName == "cyan") {
            return Color.green + Color.blue;
        }
    }
}

不允許合併

並非TypeScript中允許所有合併。 目前,類不能與其他類或變數合併。 有關模擬類合併的資訊,請參閱TypeScript中的Mixins部分。

模組擴充套件

雖然JavaScript模組不支援合併,但您可以通過匯入然後更新它們來修補現有物件。 讓我們看一下玩具Observable示例:

// observable.js
export class Observable<T> {
    // ... implementation left as an exercise for the reader ...
}

// map.js
import { Observable } from "./observable";
Observable.prototype.map = function (f) {
    // ... another exercise for the reader
}

這在TypeScript中也可以正常工作,但編譯器不瞭解Observable.prototype.map。 您可以使用模組擴充來告訴編譯器:

// observable.ts stays the same
// map.ts
import { Observable } from "./observable";
declare module "./observable" {
    interface Observable<T> {
        map<U>(f: (x: T) => U): Observable<U>;
    }
}
Observable.prototype.map = function (f) {
    // ... another exercise for the reader
}


// consumer.ts
import { Observable } from "./observable";
import "./map";
let o: Observable<number>;
o.map(x => x.toFixed());

模組名稱的解析方式與匯入/匯出中的模組說明符相同。 有關更多資訊,請參閱模組 然後合併擴充中的宣告,就好像它們在與原始檔案相同的檔案中宣告一樣。 但是,您無法在擴充中宣告新的頂級宣告 - 只是現有宣告的補丁。

全域性擴充套件您還可以從模組內部向全域性範圍新增宣告:

// observable.ts
export class Observable<T> {
    // ... still no implementation ...
}

declare global {
    interface Array<T> {
        toObservable(): Observable<T>;
    }
}

Array.prototype.toObservable = function () {
    // ...
}

全域性擴充套件與模組擴充套件具有相同的行為和限制。