美文网首页我爱编程
TypeScript 学习笔记 之 声明合并

TypeScript 学习笔记 之 声明合并

作者: 一半晴天 | 来源:发表于2018-03-12 16:18 被阅读145次

声明合并(declaration merging)指的是 TSC 将多个同名的声明合并到同一个定义中。

基本概念

TS 中有 namespace,type,value 三种实体。声明便是创建实体。

合并接口

例如:

interface Box{
  height: number;
  width: number;
}
interface Box{
  scale: number;
}
let box: Box = {height: 5, width: 6, scale: 10};
  1. 如果多个接口中的同名属性类型不一致的话,编译器会报错。
  2. 方法的合并一般是后面的声明排在前面的重载,如果是参数是字符串字面量则会提前。
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;
}

会合并成:

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

命名空间的合并

合并之后,原来命名空间没有 export 的东西,不能其他同名命名空间直接访问。

合并 带类,函数,枚举的命名空间。

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 = {}));

所以也可以借助命名空间的合并以实现扩展已有的类,函数,枚举等功能。
比如扩展函数 :

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 = {}));

合并的限制,类不能跟类及其他变量合并。

模块增强

在 JS 中通过导入对象并更新。
如:

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

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

TS 中也可以,不过编译器不知道 Observable.prototype.map 需要通过模块增强来声明:

// 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());

原来的模块正常解析之后,在增强的声明会被合并就好比像在同一个文件中声明一样。不过不能声明新的顶级声明。只能修改已有的声明。

全局增强

也可以在模块内部为全局作用域添加声明。
示例如下:

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

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

参考: Declaration Merging

相关文章

网友评论

    本文标题:TypeScript 学习笔记 之 声明合并

    本文链接:https://www.haomeiwen.com/subject/gkcpfftx.html