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