TypeScript 學(xué)習(xí)筆記 之 聲明合并

聲明合并(declaration merging)指的是 TSC 將多個(gè)同名的聲明合并到同一個(gè)定義中。

基本概念

TS 中有 namespace,type,value 三種實(shí)體。聲明便是創(chuàng)建實(shí)體。

合并接口

例如:

interface Box{
  height: number;
  width: number;
}
interface Box{
  scale: number;
}
let box: Box = {height: 5, width: 6, scale: 10};
  1. 如果多個(gè)接口中的同名屬性類型不一致的話,編譯器會(huì)報(bào)錯(cuò)。
  2. 方法的合并一般是后面的聲明排在前面的重載,如果是參數(shù)是字符串字面量則會(huì)提前。
interface Document {
    createElement(tagName: any): Element;
}
interface Document {
    createElement(tagName: "div"): HTMLDivElement;
    createElement(tagName: "span"): HTMLSpanElement;
}
interface Document {
    createElement(tagName: string): HTMLElement;
    createElement(tagName: "canvas"): HTMLCanvasElement;
}

會(huì)合并成:

interface Document {
    createElement(tagName: "canvas"): HTMLCanvasElement;
    createElement(tagName: "div"): HTMLDivElement;
    createElement(tagName: "span"): HTMLSpanElement;
    createElement(tagName: string): HTMLElement;
    createElement(tagName: any): Element;
}

命名空間的合并

合并之后,原來命名空間沒有 export 的東西,不能其他同名命名空間直接訪問。

合并 帶類,函數(shù),枚舉的命名空間。

class Album{
  label: Album.AlbumLabel;
}
namespace Album{
  export class AlbumLabel{}
}

將編譯成如下代碼:

var Album = /** @class */ (function () {
    function Album() {
    }
    return Album;
}());
(function (Album) {
    var AlbumLabel = /** @class */ (function () {
        function AlbumLabel() {
        }
        return AlbumLabel;
    }());
    Album.AlbumLabel = AlbumLabel;
})(Album || (Album = {}));

所以也可以借助命名空間的合并以實(shí)現(xiàn)擴(kuò)展已有的類,函數(shù),枚舉等功能。
比如擴(kuò)展函數(shù) :

function buildLabel(name:string):string{
    return buildLabel.prefix + name + buildLabel.suffix;
}
namespace buildLabel{
    export let suffix = "";
    export let prefix = "hello,";
}
?

編譯成:

function buildLabel(name) {
    return buildLabel.prefix + name + buildLabel.suffix;
}
(function (buildLabel) {
    buildLabel.suffix = "";
    buildLabel.prefix = "hello,";
})(buildLabel || (buildLabel = {}));

合并的限制,類不能跟類及其他變量合并。

模塊增強(qiáng)

在 JS 中通過導(dǎo)入對(duì)象并更新。
如:

// observable.js
export class Observable<T> {}

// map.js
import { Observable } from "./observable";
Observable.prototype.map = function (f) {}

TS 中也可以,不過編譯器不知道 Observable.prototype.map 需要通過模塊增強(qiáng)來聲明:

// observable.ts 同上
// 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) {
}


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

原來的模塊正常解析之后,在增強(qiáng)的聲明會(huì)被合并就好比像在同一個(gè)文件中聲明一樣。不過不能聲明新的頂級(jí)聲明。只能修改已有的聲明。

全局增強(qiáng)

也可以在模塊內(nèi)部為全局作用域添加聲明。
示例如下:

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

declare global{
   interface Array<T>{
      toObservable(): Observable<T>;
   }
}
Array.prototype.toObservable = function(){
}

參考: Declaration Merging

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容