关于术语的说明:需要注意的是,在 TypeScript 1.5 中,术语发生了变化。“内部模块”现在是“命名空间”。“外部模块”现在只是“模块”,目的是与 ECMAScript 2015 的术语保持一致(即
module X {
等效于现在更常用的namespace X {
)。
这篇文章概述了使用 TypeScript 中的命名空间(以前称为“内部模块”)组织代码的各种方法。正如我们在术语说明中提到的,“内部模块”现在称为“命名空间”。此外,在声明内部模块时任何使用 module
关键字的地方都可以且应该改用 namespace
关键字。这避免了通过类似命名的术语让新用户感到困惑。
第一步
让我们从我们将在本页中用作示例的程序开始。我们编写了一小套简单的字符串验证器,就像您在网页中检查用户在表单上的输入或检查外部提供的数据文件的格式时所编写的那样。
单个文件中的验证器
ts
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 trylet strings = ["Hello", "98052", "101"];// Validators to uselet validators: { [s: string]: StringValidator } = {};validators["ZIP code"] = new ZipCodeValidator();validators["Letters only"] = new LettersOnlyValidator();// Show whether each string passed each validatorfor (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
为它们加前缀。相反,变量 lettersRegexp
和 numberRegexp
是实现细节,因此它们保持未导出,并且在命名空间之外的代码中不可见。在文件底部的测试代码中,我们现在需要限定在命名空间外使用的类型名称,例如 Validation.LettersOnlyValidator
。
命名空间验证器
ts
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 trylet strings = ["Hello", "98052", "101"];// Validators to uselet validators: { [s: string]: Validation.StringValidator } = {};validators["ZIP code"] = new Validation.ZipCodeValidator();validators["Letters only"] = new Validation.LettersOnlyValidator();// Show whether each string passed each validatorfor (let s of strings) {for (let name in validators) {console.log(`"${s}" - ${validators[name].isAcceptable(s) ? "matches" : "does not match"} ${name}`);}}
跨文件拆分
随着我们应用程序的增长,我们将希望将代码拆分为多个文件,以便于维护。
多文件命名空间
在这里,我们将把我们的 Validation
命名空间拆分为多个文件。即使这些文件是分开的,它们也可以为同一个命名空间做出贡献,并且可以像在同一个地方定义一样被使用。由于文件之间存在依赖关系,我们将添加引用标签来告诉编译器文件之间的关系。我们的测试代码保持不变。
Validation.ts
ts
namespace Validation {export interface StringValidator {isAcceptable(s: string): boolean;}}
LettersOnlyValidator.ts
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
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);}}}