本文概述了TypeScript中如何使用模块以各种方式来组织代码。我们将涵括内部和外部的模块,并且讨论他们在适合在何时使用和怎么使用。我们也会学习一些如何使用外部模块的高级技巧,并且解决一些当我们使用TypeScript的模块时遇到的陷阱。
案例的基础
接下来开始写程序,我们将会在这里写上使用案例。我们来写个小型的简单字符串验证器,在我们检查网页上表单的input用户名或者检查外部数据文件格式的时候可能会用到。
单一的验证器:
interface StringValidator {
isAcceptable(s: string): boolean;
}var lettersRegexp = /^[A-Za-z]+$/;var 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);
}
}// 针对以下集合中的字符串做一些简单的测试var strings = ['Hello', '98052', '101'];// 使用验证器var validators: { [s: string]: StringValidator; } = {};
validators['ZIP code'] = new ZipCodeValidator();
validators['Letters only'] = new LettersOnlyValidator();// 展示每个字符串通过验证器后的结果strings.forEach(s => { for (var name in validators) {
console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
}
});
使用模块
当需要添加更多验证的时候,我们想要有一个可以跟踪类型并且不用担心与其他对象名称产生冲突的组织方案。将对象包装成一个模块,代替把大量不同的名称放在全局命名空间中。
在这个例子中,我们把验证器相关的类型都放进一个名为"Validation"的模块。因为我们希望这些接口和类在模块外是可见的,所以对他们进行export。相反, lettersRegexp和numberRegexp变量是实现功能的细节,因此不必要去导出他们,那么他们在模块外是不可见的。在文件底部的测试代码中,当在模块外使用的时候需要指定类型的名称,如"Validation.LettersOnlyValidator"。
模块化的验证器
module Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
} var lettersRegexp = /^[A-Za-z]+$/; var 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);
}
}
}// 针对以下集合中的字符串做一些简单的测试var strings = ['Hello', '98052', '101'];// 使用验证器var validators: { [s: string]: Validation.StringValidator; } = {};
validators['ZIP code'] = new Validation.ZipCodeValidator();
validators['Letters only'] = new Validation.LettersOnlyValidator();// 展示每个字符串通过验证器后的结果strings.forEach(s => { for (var name in validators) {
console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
}
});
拆分文件
随着我们应用程序的扩展,我们希望将代码拆分成多个文件使其更方便维护。现在,将上面的验证器模块拆分了放到多个文件中。虽然每个文件是单独的,但他们都在为同一个模块贡献功能,并且在代码中定义他们的时候就会被调用。因为每个文件是相互依赖的,我们已经添加了"reference"标签来告诉编译器文件之间的关系。实际上,我们的测试代码并没有改变。
多文件的内部模块:
Validation.ts
module Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
}
LettersOnlyValidator.ts
/// <reference path="Validation.ts" />module Validation { var lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) { return lettersRegexp.test(s);
}
}
}
ZipCodeValidator.ts
/// <reference path="Validation.ts" />module Validation { var numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s);
}
}
}
Test.ts
/// <reference path="Validation.ts" />/// <reference path="LettersOnlyValidator.ts" />/// <reference path="ZipCodeValidator.ts" />// 针对以下集合中的字符串做一些简单的测试var strings = ['Hello', '98052', '101'];// 使用验证器var validators: { [s: string]: Validation.StringValidator; } = {};
validators['ZIP code'] = new Validation.ZipCodeValidator();
validators['Letters only'] = new Validation.LettersOnlyValidator();// 展示每个字符串通过验证器后的结果strings.forEach(s => { for (var name in validators) {
console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
}
});
一旦有多个文件参与项目,我们得确保所需编译的代码是否都已加载,有两种方式可以实现。
我们可以使用 -out 将所有的文件内容输出到一个单独的JavaScript文件中:
tsc --out your.js Test.ts
编译器会根据文件中的"reference"标签自动地将输出文件进行有序的排序,你也可以指定输出到单独的文件:
tsc --out your.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts
或者我们也可以对每个文件进行单独的编译。如果产生多个js文件,我们就需要使用