Typescript学习笔记(五)模块机制
javascript从es5之前都缺少⼀种模块机制,⽆法通过js引⼊⽂件,于是requirejs等等的加载器应运⽽⽣。这些加载器的使⽤也并不统⼀,产⽣了amd,commonjs,umd等等的规范,各有所长,直到es6的发布,js⾃⾝引⼊的模块机制,将会在以后逐渐被应⽤起来。
Typescrit的模块机制与es6的模块基本类似,也提供了转换为amd,es6,umd,commonjs,system的转换,⼀会我们通过⼀个简单的例⼦来运⾏⼀下ts的模块。
ts特殊的内联标签。
/// <reference path="revence.ts" />
三个斜线,reference标签,path指向引⼊的⽂件,引⼊的⽂件呢,需要定义⼀个命名空间来引⽤定义的东西。
revence.ts
namespace Validation {
const ac = "abc";
export  function a(){
console.log("module be loaded");
}
}
定义⼀个名为Validation的命名空间,导出⽤export导出。这⾥Validation下的a函数被导出,引⽤的时候就可以⽤Validation.a()来引⽤它。
text.ts
/// <reference path="revence.ts" />
Validation.a();
main⽂件是这个text.ts,引⽤了revence⽂件。编译器怎么编译它呢?
两种⽅法:⼀,把所有的输⼊⽂件编译为⼀个输出⽂件,需要使⽤--outFile标记:
tsc text.ts --outFile a.js
这样输出⽂件都会在a.js中,⽹页script引⼊了。
    ⼆,我们可以编译每⼀个⽂件(默认⽅式),那么每个源⽂件都会对应⽣成⼀个JavaScript⽂件。 然后,在页⾯上通过<script>标签把所有⽣成的JavaScript⽂件按正确的顺序引进来,⽐如:
tsc --outFile sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts
  <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" />
接下来就是ts的模块机制,⽽⾮script加载机制了。
关键词:import,export。同es6。
通过export关键词导出,包括interface的任何东西都会被导出。⽐如
export const numberRegexp = /^[0-9]+$/;
export interface StringValidator {
isAcceptable(s: string): boolean;
}
export class ParseIntBasedZipCodeValidator {
isAcceptable(s: string) {
return s.length === 5 && parseInt(s).toString() === s;
}
}
不⽤关⼼导出内容是什么,反正通过export已把这些东西都导出了。
1。重新导出。as相当于重命名,from之后的是导⼊的地址,这相当于从./ZipCodeValidator中把ZipCodeValidator导⼊,重命名为RegExpBasedZipCodeValidator再导出。记住⽤法即可。
// 导出原先的验证器但做了重命名
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
2。整合导出。*相当于全部导出。下⾯代码整合了3个⽂件,并全部导出。
export * from "./StringValidator"; // exports interface StringValidator
export * from "./LettersOnlyValidator"; // exports class LettersOnlyValidator
export * from "./ZipCodeValidator";  // exports class ZipCodeValidator
导⼊关键字是import。
import基本⽤法
import { ZipCodeValidator } from "./ZipCodeValidator";
let myValidator = new ZipCodeValidator();
这⾥./ZipCodeValidator导出的东西⾥⾯有个名字叫ZipCodeValidator的,⽤它的名字导⼊。这⾥{xxx}={123},就是这种形式,其实⽤到了es6的解构赋值。不懂的转战es6。调⽤⽤其名字直接调⽤就可以了。
1。导⼊重命名
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator = new ZCV();
as语法,重命名为ZCV
2。导⼊全部
import * as validator from "./ZipCodeValidator";
let myValidator = new validator.ZipCodeValidator();
这⾥导⼊了./ZipCodeValidator⽂件的所有导出,⽽不是上个例⼦仅导⼊ZipCodeValidator。as validator相当于给了所有导出⼀个名字,可以理解为所有导出的命名空间。
Tips:学javascript前要学什么
尽管不推荐这么做,⼀些模块会设置⼀些全局状态供其它模块使⽤。 这些模块可能没有任何的导出或⽤户根本就不关注它的导出。 使⽤下⾯的⽅法来导⼊这类模块:
import "./my-module.js";
3。默认导出。default
⽐如
declare let $: JQuery;
export default $;
引⽤
import $ from "JQuery";
$("inue").html( "" );
default只能导出⼀项,仅导出⼀个函数,或者⼀个接⼝,或者任何⼀个单项的东西,default是最佳实践。因为在import的时候不指定导⼊的东西默认导⼊default。看下⾯这个例⼦
export default class ZipCodeValidator {
static numberRegexp = /^[0-9]+$/;
isAcceptable(s: string) {
return s.length === 5 && st(s);
}
}
import validator from "./ZipCodeValidator";
let validator = new validator();
4。export = 和 import = require()
TypeScript模块⽀持export =语法,以配合传统的CommonJS和AMD的⼯作流。
export =语法定义⼀个模块的导出对象。 它可以是类,接⼝,命名空间,函数或枚举。
若要导⼊⼀个使⽤了export =的模块时,必须使⽤TypeScript提供的特定语法import let = require("module")。
let numberRegexp = /^[0-9]+$/;
class ZipCodeValidator {
isAcceptable(s: string) {
return s.length === 5 && st(s);
}
}
export = ZipCodeValidator;
import zip = require("./ZipCodeValidator");
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validator = new zip.ZipCodeValidator();
/
/ Show whether each string passed each validator
strings.forEach(s => {
console.log(`"${ s }" - ${ validator.isAcceptable(s) ? "matches" : "does not match" }`);
});
5。编译为其他模块标准。
SimpleModule.ts
import m = require("mod");
export let t = m.something + 1;
AMD / RequireJS SimpleModule.js
define(["require", "exports", "./mod"], function (require, exports, mod_1) {
exports.t = mod_1.something + 1;
});
CommonJS / Node SimpleModule.js
let mod_1 = require("./mod");
exports.t = mod_1.something + 1;
UMD SimpleModule.js
(function (factory) {
if (typeof module === "object" && ports === "object") {
let v = factory(require, exports); if (v !== undefined) ports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "./mod"], factory);
}
})(function (require, exports) {
let mod_1 = require("./mod");
exports.t = mod_1.something + 1;
});
System SimpleModule.js
let mod_1;
let t;
return {
setters:[
function (mod_1_1) {
mod_1 = mod_1_1;
}],
execute: function() {
exports_1("t", t = mod_1.something + 1);
}
}
});
Native ECMAScript 2015 modules SimpleModule.js
import { something } from "./mod";
export let t = something + 1;
命令⾏的命令就是加 --module或者-m加要编译的规范名称。⽐如编译为amd
tsc text.ts -m amd
⽤tsc --help可以看到-m的各项参数。
⾼级加载
typescript的按需加载。也叫动态加载。看我博客前⼏篇的webpack中,⽤的sure做按需加载,感觉⽐较⿇烦。然⽽ts的按需加载的简单得益于它的省略引⽤。即:
编译器会检测是否每个模块都会在⽣成的JavaScript中⽤到。 如果⼀个模块标识符只在类型注解部分使⽤,并且完全没有在表达式中使⽤时,就不会⽣成require这个模块的代码。 省略掉没有⽤到的引⽤对性能提升是很有益的,并同时提供了选择性加载模块的能⼒。
这种模式的核⼼是import id = require("...")语句可以让我们访问模块导出的类型。 模块加载器会被动态调⽤(通过require)
⽰例:Node.js⾥的动态模块加载
declare function require(moduleName: string): any;
import { ZipCodeValidator as Zip } from "./ZipCodeValidator";
if (needZipValidation) {
let ZipCodeValidator: typeof Zip = require("./ZipCodeValidator");
let validator = new ZipCodeValidator();
if (validator.isAcceptable("...")) { /* ... */ }
}
⽰例:require.js⾥的动态模块加载
declare function require(moduleNames: string[], onLoad: (...args: any[]) => void): void; import { ZipCodeValidator as Zip } from "./ZipCodeValidator";
if (needZipValidation) {
require(["./ZipCodeValidator"], (ZipCodeValidator: typeof Zip) => {
let validator = new ZipCodeValidator();
if (validator.isAcceptable("...")) { /* ... */ }
});
}
只要if条件不成⽴,模块是不加载的。出个简单的例⼦:
text.ts
import m= require("revence");
export let t=1;;
revence.ts
export = {
mod:1
}
编译为amd模块:根本没有引⼊刚才的模块。
define(["require", "exports"], function (require, exports) {
exports.t = 1;
;
});
现在改为text.ts
import m= require("revence");
export let d+1;;
编译出来为
define(["require", "exports", "revence"], function (require, exports, m) {
exports.t = m.mod + 1;
;
});
模块加载的最佳实践
1。尽可能地在顶层导出

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。