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

基础概念

合并接口

接口的非函数的成员应该是唯一的。 如果它们不是唯一的,那么它们必须是相同的类型。 如果两个接口中同时声明了同名的非函数成员且它们的类型不同,则编译器会报错。
对于函数成员,每个同名函数声明都会被当成这个函数的一个重载。 同时需要注意,当接口A与后来的接口A合并时,后面的接口具有更高的优先级
这个规则有一个例外是当出现特殊的函数签名时。 如果签名里有一个参数的类型是单一的字符串字面量(比如,不是字符串字面量的联合类型),那么它将会被提升到重载列表的最顶端。比如以下这种:

  1. createElement(tagName: "div"): HTMLDivElement;

合并命名空间

对于命名空间的合并,模块导出的同名接口进行合并,构成单一命名空间内含合并后的接口。
对于命名空间里值的合并,如果当前已经存在给定名字的命名空间,那么后来的命名空间的导出成员会被加到已经存在的那个模块里。
除了这些合并外,你还需要了解非导出成员是如何处理的。 非导出成员仅在其原有的(合并前的)命名空间内可见。这就是说合并之后,从其它命名空间合并进来的成员无法访问非导出成员。

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

  1. enum Color {
  2. red = 1,
  3. green = 2,
  4. blue = 4
  5. }
  6. namespace Color {
  7. export function mixColor(colorName: string) {
  8. if (colorName == "yellow") {
  9. return Color.red + Color.green;
  10. }
  11. else if (colorName == "white") {
  12. return Color.red + Color.green + Color.blue;
  13. }
  14. else if (colorName == "magenta") {
  15. return Color.red + Color.blue;
  16. }
  17. else if (colorName == "cyan") {
  18. return Color.green + Color.blue;
  19. }
  20. }
  21. }

非法的合并

TypeScript并非允许所有的合并。 目前,类不能与其它类或变量合并

模块扩展

  1. // observable.ts
  2. export class Observable<T> {
  3. // ... implementation left as an exercise for the reader ...
  4. }
  5. // map.ts
  6. import { Observable } from "./observable";
  7. declare module "./observable" {
  8. interface Observable<T> {
  9. map<U>(f: (x: T) => U): Observable<U>;
  10. }
  11. }
  12. Observable.prototype.map = function (f) {
  13. // ... another exercise for the reader
  14. }
  15. // consumer.ts
  16. import { Observable } from "./observable";
  17. import "./map";
  18. let o: Observable<number>;
  19. o.map(x => x.toFixed())

模块名的解析和用import/export解析模块标识符的方式是一致的。 更多信息请参考 Modules。 当这些声明在扩展中合并时,就如同在原始位置被声明一样。 但是,有两点限制需要注意:

  1. 你不能在扩展中声明新的顶级声明——仅可以扩展模块中已经存在的声明。
  2. 默认导出也不能扩展,只有命名的导出才可以(因为你需要使用导出的名字来进行扩展,并且default是保留关键字

    全局扩展

    全局扩展与模块扩展的行为和限制是相同的。 ```typescript // observable.ts export class Observable { // … still no implementation … }

declare global { interface Array { toObservable(): Observable; } }

Array.prototype.toObservable = function () { // … } ```