当前位置:
首页
文章
前端
详情

TypeScript手册翻译系列4

模块

在TypeScript中利用模块(module)来组织代码。这里将讨论内部和外部模块,以及在何时使用哪种方式更合适,以及怎么使用。当然也会讨论一些高级话题,例如如何使用外部模块,以及在TypeScript中使用模块时常见的一些错误。

第一步

让我们从下面的例子开始,这个例子将会贯穿本文。首先我们写了一段字符串验证代码,用来验证用户在web页面表单输入的信息,或者是检查外部文件提供的数据格式。

在单个文件中的Validator

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

// Some samples to try
var strings = ['Hello', '98052', '101'];

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

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

增加模块

当增加更多的验证逻辑时,我们希望利用某种组织方式跟踪验证类型,而不必担心与其他对象的名称冲突。不是将大量的不同名称放在全局命名空间中,而是将对象封装成模块。

在下面例子中,我们将把所有与validator相关的类型都移到一个'Validation'模块中。因为我们希望接口和类对外部模块可见,所以我们在前面加上了'export'关键字导出接口和类。相反,变量lettersRegexp和numberRegexp是实现细节,我们并不希望暴露给外部模块。在文件最后面的测试代码中,要想在外部模块使用就需要用模块名称限定类型名称,例如Validation.LettersOnlyValidator。

模块化的Validators

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

// Some samples to try
var strings = ['Hello', '98052', '101'];

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

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

拆分为多个文件

随着应用程序的增长,希望将代码分为多个文件,使维护更容易。
下面,将Validation模块的内容分到多个文件中。虽然这些文件是分开的,但每一个文件都对同一个模块做出贡献,当使用时就像是在一个地方定义的。由于文件之间存在依赖关系,因此我们添加了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" />
// Some samples to try
var strings = ['Hello', '98052', '101'];

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

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

一旦涉及多个文件,就需要保证编译器能加载各个文件。这里有两种方式做到:

第一种方式:可以利用 --out flag连接多个输入文件让编译器编译输出一个JavaScript文件。

tsc --out sample.js Test.ts

编译器会根据文件中的reference标签排序输出文件。

也可以指定每一个文件:

tsc --out sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts

第二种方式:可以对每个输入文件单独编译(缺省方式)生成一个JavaScript文件。如果生成了多个JS文件,可以在web页面按照一定的顺序使用