zoukankan      html  css  js  c++  java
  • TS 3.1

    总结

    • 同名的命名空间、模块下
      - 接口支持合并。
      - 枚举的实现和接口支持合并。
      - 表示函数的接口在合并时有比较特殊的规则,其他合并规则都遵循后合并的在前。
      - 命名空间在模块体系中不推荐使用,模块已经原生支持了,也不建议通过 module 创建。所以这个规则没有太大的意义。只适合用来拓展类型,而不适合拓展实现。
    • 命名空间和模块本身也类型和实现的合并
      - 会按类型种类进行合并,先合并接口后合并 class,其他顺序不清楚,似乎也不关心
      - 非导出成员在各自命名空间、模块中是独立的。
      - 实现的合并没有什么用,模块模式中不建议使用命名空间。适用于扩展外部模块的类型。
    • 命名空间还能够和 class、函数的实现进行合并
      - 命名空间和 class 必须同名
      - 命名空间必须在 class 后定义
      - 命名空间扩展了 class 的静态端,即給一个函数对象添加了某些属性。
    • 命名空间还能够和枚举的实现进行合并,即给枚举对象扩展了属性。

    原文地址 www.tslang.cn

    介绍

    对本文件来讲,“声明合并” 是指编译器将针对同一个名字的两个独立声明合并为单一声明。 合并后的声明同时拥有原先两个声明的特性。 任何数量的声明都可被合并;不局限于两个声明。

    基础概念

    TypeScript 中的声明会创建以下三种实体之一:命名空间,类型或值。 创建命名空间的声明会新建一个命名空间,它包含了用(.)符号来访问时使用的名字。 创建类型的声明是:用声明的模型创建一个类型并绑定到给定的名字上。 最后,创建值的声明会创建在 JavaScript 输出中看到的值。

    注释:表格中的 X 是指拥有。

    Declaration TypeNamespaceTypeValue
    NamespaceXX
    ClassXX
    EnumXX
    InterfaceX
    Type AliasX
    FunctionX
    VariableX

    合并接口

    最简单也最常见的声明合并类型是接口合并。 从根本上说,合并的机制是把双方的成员放到一个同名的接口里。

    注释:一个模块中允许有同名的接口

    interface Box {
        height: number;
         number;
    }
    
    interface Box {
        scale: number;
    }
    
    let box: Box = {height: 5,  6, scale: 10};
    

    接口的非函数的成员应该是唯一的。如果它们不是唯一的,那么它们必须是相同的类型。如果两个接口中同时声明了同名的非函数成员且它们的类型不同,则编译器会报错。

    注释:以下为用接口声明函数的类型

    对于函数成员,每个同名函数声明都会被当成这个函数的一个重载。 同时需要注意,当接口 A与后来的接口 A合并时,后面的接口具有更高的优先级。

    如下例所示:

    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;
    }
    interface Document {
        createElement(tagName: "div"): HTMLDivElement;
        createElement(tagName: "span"): HTMLSpanElement;
    }
    interface Document {
        createElement(tagName: string): HTMLElement;
        createElement(tagName: "canvas"): HTMLCanvasElement;
    }
    

    合并后的 Document将会像下面这样:

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

    合并命名空间

    与接口相似,同名的命名空间也会合并其成员。 命名空间会创建出命名空间和值,我们需要知道这两者都是怎么合并的。

    对于命名空间的合并,模块导出的同名接口进行合并,构成单一命名空间内含合并后的接口。

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

    Animals声明合并示例:

    namespace Animals {
        export class Zebra { }
    }
    
    namespace Animals {
        export interface Legged { numberOfLegs: number; }
        export class Dog { }
    }
    

    等同于:

    namespace Animals {
        export interface Legged { numberOfLegs: number; }
    
        export class Zebra { }
        export class Dog { }
    }
    

    除了这些合并外,你还需要了解非导出成员是如何处理的。 非导出成员仅在其原有的(合并前的)命名空间内可见。这就是说合并之后,从其它命名空间合并进来的成员无法访问非导出成员。

    下例提供了更清晰的说明:

    namespace Animal {
        let haveMuscles = true;
    
        export function animalsHaveMuscles() {
            return haveMuscles;
        }
    }
    
    namespace Animal {
        export function doAnimalsHaveMuscles() {
            return haveMuscles;  // Error, because haveMuscles is not accessible here
        }
    }
    

    命名空间与类和函数和枚举类型合并

    命名空间可以与其它类型的声明进行合并。 只要命名空间的定义符合将要合并类型的定义。合并结果包含两者的声明类型。 TypeScript 使用这个功能去实现一些 JavaScript 里的设计模式。

    注释:命名空间和 class 必须同名,class 内可以通过 命名空间. 来访问命名空间中的类型和实例;

    合并命名空间和类

    这让我们可以表示内部类。

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

    合并规则与上面 合并命名空间小节里讲的规则一致,我们必须导出 AlbumLabel类,好让合并的类能访问。 合并结果是一个类并带有一个内部类。 你也可以使用命名空间为类增加一些静态属性。

    注释:以下例子更能表现命名空间和 class 合并的作用,用于扩展类的静态端

    class Album2 {}
    namespace Album2 {
      export const AlbumLabel = "1";
    }
    
    console.log(Album2.AlbumLabel,new Album2());
    

    注释:以下为合并函数和命名空间

    除了内部类的模式,你在 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 的混入

  • 相关阅读:
    一个好的时间函数
    Codeforces 785E. Anton and Permutation
    Codeforces 785 D. Anton and School
    Codeforces 510 E. Fox And Dinner
    Codeforces 242 E. XOR on Segment
    Codeforces 629 E. Famil Door and Roads
    Codeforces 600E. Lomsat gelral(Dsu on tree学习)
    Codeforces 438D The Child and Sequence
    Codeforces 729E Subordinates
    【ATcoder】D
  • 原文地址:https://www.cnblogs.com/qq3279338858/p/14340161.html
Copyright © 2011-2022 走看看