美文网首页我爱编程
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