1
typescript之旅

1.TypeScript-Basic
2.TypeScript interface
3.Typescript-module(1)
4.TypeScript Modules(2)
5.Typescript tsconfig
6.TypeScript Functions
7.Typescript Class

Namespace

模块化开发是我们组织代码或团队开发最重要的一课。你想想,以一个类似于processon的在线画图系统为例。如果UML节点的绘制,Canvas画布的操作,鼠标事件,快捷键事件,各种约束条件的加入,这么一个上万行的文件,打开文件要2分钟,找一行代码都得3分钟,还怎么维护?如果我想加一个变量,自己钟意的变量名和前人的冲突,最后只能委屈的用了一个不合适的名称,代码越来越难看懂,整夜整夜加班。

第一步

以一个例子说明,在网页中经常需要检验用户的输入是否合法,我们写了一个简单的字符串校验器。


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

interface StringValidator {
    isAcceptable(s: string): boolean;
}

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

解决之道模块化

namespace关键字

解决问题: 划分命名空间

namespace 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的命名空间(这里使用的是namespace Validation ,也可以使用module Validation,推荐使用前者-namespace)。

  • namespace相当于一个封闭的module,如何使用里面的声明或变量呢?export关键字可以使interface,class等在外部可见。而变量lettersRegexpnumberRegexp外部不可见。

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

ok,我们划分了多个命名空间,现在可以安心的使用变量名,不用担心和别人冲突了。但是上万行的代码怎么分割成多个文件呢?(util工具函数一个文件,业务代码一个文件,多清楚!)

分割代码

Validation.ts

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

LettersOnlyValidator.ts

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

ZipCodeValidator.ts

/// <reference path="Validation.ts" />
namespace 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);
    }
});

注意
<reference path="Validation.ts" />如果没有这句,你就无法引用Validation.ts文件中声明的class.好啦,我知道语法很奇葩,不过也有好处啊!

  • 一行命令编译好
    tsc --out sample.js Test.ts

编译器根据Test.ts中声明的reference,顺序地导入并编译成一个文件sample.js

  • 有时候如果你有特殊需求,比方说不想合并这些文件,导致sample.js太长,在chrome developer tools中调试时,跳的太远。你可以分别编译,然后再html中引入

    <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" />

Sike
272 声望18 粉丝