TS:声明合并de妙处

TS:声明合并

一、基础概念

  • 声明合并是指编译器将针对同一名字的多个独立声明合并为单一声明。
  • 合并后的声明同时拥有多个声明的特性。

二、声明合并的种类

1. 接口合并

  • 接口合并的机制时将双方的成员放到一个同名的接口里;

  • 接口里的非函数成员必须是唯一的,如果不唯一,必须是统一类型的;如果声明了同名的非函数成员但是类型不同,编译器就会报错;

    interface Animal {
          
          
        name : string;
        age : number;
    }
    interface Animal {
          
          
        kind : string;
    }
    
    let cat : Animal = {
          
          
        name : 'hellokitty',
        age : 5,
        kind : cat
    }	// ok
    
  • 对于函数成员,每个同名函数声明都会被当成这个函数的一个重载。

  • 同时需要注意,后面声明的接口具有更高的优先级。

    interface Cloner {
          
          
        clone(animal: Animal): Animal;
    }
    
    interface Cloner {
          
          
        clone(animal: Sheep): Sheep;
    }
    
    interface Cloner {
          
          
        clone(animal: Dog): Dog;
        clone(animal: Cat): Cat;
    }
    
    // 等同于
    
    interface Cloner {
          
          
        clone(animal: Dog): Dog;
        clone(animal: Cat): Cat;
        clone(animal: Sheep): Sheep;
        clone(animal: Animal): Animal;
    }
    
  • 这个规则有一个例外是当出现特殊的函数签名时,如果签名里有一个参数的类型是 单一的字符串字面量(比如,不是字符串字面量的联合类型),那么它将会被提升到重载列表的最顶端。

    interface Document {
          
          
        createElement(tagName : any) : Element;
        createElement(tagName : "div") : HTMLDivElement;
    }
    
    interface Document {
          
          
        createElement(tagName : string) : HTMLELement;
        createElement(tagName : "p") : HTMLPElement;
    }
    
    // 等同与
    
    interface Document {
          
          
        createElement(tagName: "div"): HTMLDivElement;
        createElement(tagName: "p"): HTMLPElement;
        createElement(tagName: string): HTMLElement;
        createElement(tagName: any): Element;
    }
    

2. 合并命名空间

  • 对于命名空间里导出成员的合并,如果当前已经存在给定名字的命名空间,那么后来的命名空间的导出成员会被加到已经存在的那个模块里。

    namespace Animal {
          
          
        export class Cat {
          
           ... }
        export class Dog {
          
           ... }
    }
        
    namespace Animal {
          
          
        export interface Motion {
          
          
            eat : (food : string)=>void;
        }
    }
    
  • 非导出成员仅在其原有的(合并前的)命名空间内可见。

  • 从其它命名空间合并进来的成员无法访问非导出成员。

3. 命名空间与类的合并

  • 命名空间可以与类进行合并,只要命名空间的定义符合即将合并的类的定义;

  • 合并规则与上面 合并命名空间小节里讲的规则一致,我们必须导出命名空间里的类,好让合并的类能访问。

  • 合并结果是一个类并带有一个内部类。 你也可以使用命名空间为类增加一些静态属性。

    class Album {
          
          
        label: Album.AlbumLabel;
    }
    namespace Album {
          
          
        export class AlbumLabel {
          
           }
    }
    
  • 除了内部类的模式,你在JavaScript里,创建一个函数稍后扩展它增加一些属性也是很常见的。 TypeScript使用声明合并来达到这个目的并保证类型安全。

    function sayHelloTo(name : string) : string {
          
          
        return sanHelloTo.prefix + name + "!";
    }
    
    namespace sayHelloTo {
          
          
        export let prefix = "Hello ";
    }
    
    console.log(sayHelloTo("yivi"));
    

4. 命名空间与枚举的合并

  • 命名空间可以用来扩展枚举:

    enum Color {
          
          
        red = 1,
        green = 2,
        blue = 3
    }
    
    namespace Color {
          
          
        export function mixColor (color : string){
          
          
            if(color == "yellow"){
          
          
                return Color.red + Color.green;
            }else if(color == "white"){
          
          
                return Color.red + Color.green + Color.blue;
            }else if(color == "cyan"){
          
          
                return Color.green + Color.blue;
            }
        }
    }
    

三、 非法合并

  • 类无法与其他类合并!类无法与其他类合并!类无法与其他类合并!

猜你喜欢

转载自blog.csdn.net/yivisir/article/details/109863275
DE