typescript之旅

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

TypeScript-Modules(2).md

Module

CMD和AMD外部依赖模块
如果你并没有使用node.js或require.js,那就没有必要使用module关键字了,只需要使用namespace

  • namespace中使用reference,module使用
    import someMod = require('someModule');

  • export功能不变,使module内部声明外部可见

  • 编译module,必须指定--module参数

tsc --module commonjs Test.ts
tsc --module amd Test.ts
  • 编译器根据import语句,顺序导入依赖文件

Validation.ts

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

LettersOnlyValidator.ts

import validation = require('./Validation');
var lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements validation.StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}

ZipCodeValidator.ts

import validation = require('./Validation');
var numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements validation.StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}

Test.ts

import validation = require('./Validation');
import zip = require('./ZipCodeValidator');
import letters = require('./LettersOnlyValidator');

// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators: { [s: string]: validation.StringValidator; } = {};
validators['ZIP code'] = new zip.ZipCodeValidator();
validators['Letters only'] = new letters.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);
    }
});

上述语法typescript编译器是如何生成代码的?

demo:

SimpleModule.ts

import m = require('mod');
export var t = m.something + 1;

AMD / RequireJS SimpleModule.js:

define(["require", "exports", 'mod'], function(require, exports, m) {
    exports.t = m.something + 1;
});

CommonJS / Node SimpleModule.js:

var m = require('mod');
exports.t = m.something + 1;

简化上面的例子

export= 语法

  • 在LettersOnlyValidator.ts中有下面的代码

import validation = require('./Validation');
...
validation. StringValidator.doSometing();

同时我们发现上面例子的两种validator,每个module都只导出一个class声明。如果使用上面的方式导出,其他文件import之后,每次都使用validation. StringValidator显得很沉重

Validation.ts

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

LettersOnlyValidator.ts

import validation = require('./Validation');
var lettersRegexp = /^[A-Za-z]+$/;
class LettersOnlyValidator implements validation.StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}
export = LettersOnlyValidator;

ZipCodeValidator.ts

import validation = require('./Validation');
var numberRegexp = /^[0-9]+$/;
class ZipCodeValidator implements validation.StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}
export = ZipCodeValidator;

Test.ts(此文件是重点,zipValidator和lettersValidator可以直接使用)

import validation = require('./Validation');
import zipValidator = require('./ZipCodeValidator');
import lettersValidator = require('./LettersOnlyValidator');

// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators: { [s: string]: validation.StringValidator; } = {};
validators['ZIP code'] = new zipValidator();
validators['Letters only'] = new lettersValidator();
// 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);
    }
});

注意
这种简化写法只使用于只导出一个声明的模块

别名

  • 另一种缩短对象引用名称的方式。

注意
别名的语法也是很奇葩的,如果名称太长,可以使用import q = x.y.z ,这个语法和import x = require('name') 没有一毛钱关系,typescript项目组的朋友们,你们加个关键字能死吗?这里的语法只是为指定的符号创建一个别名。

module Shapes {
    export module Polygons {
        export class Triangle { }
        export class Square { }
    }
}

import polygons = Shapes.Polygons;
var sq = new polygons.Square(); // Same as 'new Shapes.Polygons.Square()'

高级模块加载方式

有时候,你紧紧想在满足某些条件下,才加载某一模块

这个功能确实很赞,但是还是语法的问题,很让你困惑。

再说之前呢,有必要对这个语法进行深入了解

import zipValidator = require('./ZipCodeValidator');

按照上面的理解,大多数人肯定认为,这个语法就是nodejs中的
var zipValidator = require('./ZipCodeValidator');

这样理解也没错,但是这里有一个typescript的惰性加载问题。首先我们知道node加载外部模块是很浪费时间的,所以呢,typescript遇到这句话,并不会马上进行require调用,而是等到后面真的要用的该模块时,才会require.看例子:

Test.ts

import StringValidator = require('./Validation');
import zipValidator = require('./ZipCodeValidator');
import lettersValidator = require('./LettersOnlyValidator');

// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators: { [s: string]: StringValidator; } = {};
validators['ZIP code'] = new zipValidator();

里面的lettersValidator虽然导入了,但是后面并没有使用。
生成的js代码如下:

var zipValidator = require('./ZipCodeValidator');
// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators = {};
validators['ZIP code'] = new zipValidator();

ok,这就是我们要了解的背景,typescript的惰性加载问题

利用上面的这个特性,我们实现动态加载(nodejs和requirejs的区别)

Dynamic Module Loading in node.js

declare var require;
import Zip = require('./ZipCodeValidator');
if (needZipValidation) {
    var x: typeof Zip = require('./ZipCodeValidator');
    if (x.isAcceptable('.....')) { /* ... */ }
}

Sample: Dynamic Module Loading in require.js

declare var require;
import Zip = require('./ZipCodeValidator');
if (needZipValidation) {
    require(['./ZipCodeValidator'], (x: typeof Zip) => {
        if (x.isAcceptable('...')) { /* ... */ }
    });
}
  • 虽然我前面铺垫了很多,你看到这里,还是可能看不懂,好吧,我承认我自己在这里也纠结了好久

declare var require是表示声明nodejs中的require关键词,否则这里var x: typeof Zip = require('./ZipCodeValidator');,会报错(require未声明)。

  • 请注意这里的require是node中的require,而import Zip = require('./ZipCodeValidator');中的require是typescript的关键词,而且只能和import一起用。了解这点非常重要!!!

  • import Zip = require('./ZipCodeValidator');根据惰性加载机制,这句话什么都不会做!!!

  • typeof Zip什么意思,请回头看高级技巧

生成的js代码

if (needZipValidation) {
    var x = require('./ZipCodeValidator');
    if (x.isAcceptable('.....')) { }
}

使用第三方库

第三方库都不是typescript开发的,我们要使用的时候怎么使用呢?

第三方库api都是没有类型信息的,但是typescript编译器主要的工作就是检查类型是否匹配。我们能不能把它们的api全部声明一遍,这样我们的代码调用api的时候,编译器去检查声明类型是否一致,来提示错误。
所以要写.d.ts文件,比如D3,那就要写D3.d.ts

  • namespace
    D3.d.ts (simplified excerpt)

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;
  • module

node.d.ts (simplified excerpt)

declare module "url" {
    export interface Url {
        protocol?: string;
        hostname?: string;
        pathname?: string;
    }

    export function parse(urlStr: string, parseQueryString?, slashesDenoteHost?): Url;
}

declare module "path" {
    export function normalize(p: string): string;
    export function join(...paths: any[]): string;
    export var sep: string;
}

Now we can /// <reference> node.d.ts and then load the modules using e.g. import url = require('url');.

///<reference path="node.d.ts"/>
import url = require("url");
var myUrl = url.parse("http://www.typescriptlang.org");

Sike
272 声望18 粉丝

下一篇 »
Dot语言教程