learn-typescript

命名空间

随着 ES6 模块化的广泛使用,现在已不建议使用 TypeScript 的命名空间 namespace 作为组织代码的方式,而是推荐使用 ES6 的模块化方案。现在命名空间主要用在声明文件中。

介绍

随着一个模块中代码的增加,需要将代码分离到不同的文件中以便于维护。此时可以使用命名空间 namespace ,同一个命名空间中的代码使用起来就像是在同一个文件中。但是这些分散的文件可能存在存在依赖关系,所以需要加入引用标签(三斜线指令)来关联这些文件:

Validation.ts

namespace Validation {
  export interface StringValidator {
    isAcceptable(s: string): boolean
  }
}

LettersOnlyValidator.ts

/// <reference path="Validation.ts" />
namespace Validation {
  const lettersRegexp = /^[A-Za-z]+$/
  export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
      return lettersRegexp.test(s)
    }
  }
}

ZipCodeValidator.ts

/// <reference path="Validation.ts" />
namespace Validation {
  const numberRegexp = /^[0-9]+$/
  export class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
      return s.length === 5 && numberRegexp.test(s)
    }
  }
}

如上面代码所示,同一个 Validation 命名空间里的代码,如果有依赖关系,可以使用三斜线指令来声明,需要暴露到命名空间之外可以使用 export

外部代码调用命名空间内的代码时,需要使用三斜线指令声明引用的文件,并且需要加上命名空间(如: Validation.StringValidator)来访问其中的代码:

/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />
/// <reference path="ZipCodeValidator.ts" />

// Some samples to try
let strings = ["Hello", "98052", "101"];

// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();

// Show whether each string passed each validator
for (let s of strings) {
    for (let name in validators) {
        console.log(""" + s + "" " + (validators[name].isAcceptable(s) ? " matches " : " does not match ") + name);
    }
}

确保加载了所有代码

当使用命名空间分离代码之后,要确保加载了所有的代码:

  1. 第一种方式,把所有文件编译成一个文件:

    tsc --outFile build.js Test.ts
    
  2. 第二种方式(默认方式),为每个文件生成 js 文件,然后按正确顺序手动使用 <script> 引入页面。

为命名空间中的变量取别名

为了简化对命名空间中的变量的引用,可以使用 import q = x.y.z 给常用的对象起一个短的别名:

namespace Shapes {
  export namespace Polygons {
    export class Triangle {}
    export class Square {}
  }
}

import polygons = Shapes.Polygons
let sq = new polygons.Square() // Same as "new Shapes.Polygons.Square()"

注意:该语法不是 import module = require('module')

命名空间和模块

命名空间很难识别组件间的依赖关系,需要手动确认引入顺序,而模块没有这些问题,从 ES6 开始,模块是默认并推荐的代码组织方式。