首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Namespaces

关于术语的说明:重要的是要注意,在 TypeScript 1.5 中,命名已经改变。“内部模块”现在是“命名空间”。“外部模块”现在只是“模块”,与 ECMAScript 2015 的术语一致(即module X {相当于现在的首选namespace X {)。

介绍

本文概述了在 TypeScript 中使用名称空间(以前的“内部模块”)组织代码的各种方法。正如我们在关于术语的说明中提到的,“内部模块”现在称为“命名空间”。此外,在声明内部模块时使用关键字的任何module位置,都可以使用和应该使用namespace关键字。这避免了通过用相似命名术语重载新用户而使新用户混淆。

第一步

让我们从我们将在整个这个页面中用作我们的例子的程序开始。我们编写了一小组简单的字符串验证器,您可能会编写这些验证器来检查用户在网页表单上的输入,或者检查外部提供的数据文件的格式。

在单个文件中的验证器

代码语言:javascript
复制
interface StringValidator {
  isAcceptable(s: string): boolean;
}

let lettersRegexp = /^[A-Za-z]+$/;
let numberRegexp = /^[0-9]+$/;

class LettersOnlyValidator implements StringValidator {
  isAcceptable(s: string) {
    return lettersRegexp.test(s);
  }
}

class ZipCodeValidator implements StringValidator {
  isAcceptable(s: string) {
    return s.length === 5 && numberRegexp.test(s);
  }
}

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

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

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

命名空间

当我们添加更多验证器时,我们希望拥有某种组织方案,以便跟踪我们的类型,而不必担心与其他对象的名称冲突。我们不必将大量不同的名称放入全局名称空间,而是将我们的对象包装到名称空间中。

在这个例子中,我们将所有与验证器相关的实体移动到名为Validation空间的名称空间中。因为我们希望这里的接口和类在命名空间外部可见,所以我们在前面加上export。相反,这些变量lettersRegexpnumberRegexp实现细节,因此它们是未提交的,并且在命名空间之外的代码将不可见。在文件底部的测试代码中,我们现在需要在命名空间外使用类型的名称,例如Validation.LettersOnlyValidator

命名空间验证器

代码语言:javascript
复制
namespace Validation {
  export interface StringValidator {
    isAcceptable(s: string): boolean;
  }

  const lettersRegexp = /^[A-Za-z]+$/;
  const numberRegexp = /^[0-9]+$/;

  export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
      return lettersRegexp.test(s);
    }
  }

  export class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
      return s.length === 5 && numberRegexp.test(s);
    }
  }
}

// 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 }`);
  }
}

跨文件分割

随着我们的应用程序的增长,我们希望将代码分割成多个文件,以便于维护。

多文件命名空间

在这里,我们将把我们的Validation命名空间分割成多个文件。即使这些文件是分开的,它们每个都可以贡献给相同的名称空间,并且可以被使用,就好像它们都是在一个地方定义的一样。由于文件之间存在依赖关系,因此我们将添加引用标记以告知编译器关于文件之间的关系。我们的测试代码不变。

Validation.ts
代码语言:javascript
复制
namespace Validation {
  export interface StringValidator {
    isAcceptable(s: string): boolean;
  }
}
LettersOnlyValidator.ts
代码语言:javascript
复制
/// <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
代码语言:javascript
复制
/// <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);
    }
  }
}
Test.ts
代码语言:javascript
复制
/// <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);
  }
}

一旦涉及多个文件,我们需要确保所有已编译的代码都已加载。有两种方法可以做到这一点。

首先,我们可以使用使用--outFile标志的连接输出将所有输入文件编译为单个JavaScript输出文件:

代码语言:javascript
复制
tsc --outFile sample.js Test.ts

编译器将根据文件中存在的引用标签自动对输出文件进行排序。您也可以分别指定每个文件:

代码语言:javascript
复制
tsc --outFile sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts

或者,我们可以使用每个文件编译(默认)为每个输入文件发出一个 JavaScript 文件。如果生成了多个 JS 文件,我们需要<script>在网页上使用标签以适当的顺序加载每个发出的文件,例如:

MyTestPage.html (excerpt)
代码语言:javascript
复制
  <script src="Validation.js" type="text/javascript" />
  <script src="LettersOnlyValidator.js" type="text/javascript" />
  <script src="ZipCodeValidator.js" type="text/javascript" />
  <script src="Test.js" type="text/javascript" />

Aliases

您可以简化名称空间的另一种方法是使用import q = x.y.z为常用对象创建较短的名称。不要与import x = require("name")用于加载模块的语法混淆,该语法只是为指定的符号创建一个别名。您可以使用这些种类的导入(通常称为别名)用于任何类型的标识符,包括从模块导入创建的对象。

代码语言:javascript
复制
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()'

请注意,我们不使用require关键字; 相反,我们直接从我们导入的符号的限定名称中分配。这与使用类似var,但也适用于导入符号的类型和名称空间含义。重要的是,对于值来说,import是对原始符号的独特引用,所以对别名的更改var不会反映在原始变量中。

使用其他 JavaScript 库

为了描述不是用 TypeScript 编写的库的形状,我们需要声明库公开的 API。由于大多数 JavaScript 库仅公开一些顶级对象,因此命名空间是表示它们的好方法。

我们称这些声明没有定义“环境”实现。通常这些是在.d.ts文件中定义的。如果您熟悉 C / C ++,则可以将它们视为.h文件。我们来看几个例子。

环境命名空间

流行的库 D3 在一个全局对象中定义了它的功能d3。因为这个库是通过一个<script>标签(而不是一个模块加载器)加载的,所以它的声明使用命名空间来定义它的形状。对于 TypeScript 编译器来看这个形状,我们使用一个环境名称空间声明。例如,我们可以开始编写它,如下所示:

D3.d.ts (simplified excerpt)
代码语言:javascript
复制
declare namespace D3 {
  export interface Selectors {
    select: {
      (selector: string): Selection;
      (element: EventTarget): Selection;
    };
  }

  export interface Event {
    x: number;
    y: number;
  }

  export interface Base extends Selectors {
    event: Event;
  }
}

declare var d3: D3.Base;

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com