從ECMAScript 2015開始,JavaScript引入了模塊的概念。TypeScript也沿用這個(gè)概念。
模塊在其自身的作用域里執(zhí)行,而不是在全局作用域里;這意味著定義在一個(gè)模塊里的變量,函數(shù),類等等在模塊外部是不可見的,除非你明確地使用export形式之一導(dǎo)出它們。 相反,如果想使用其它模塊導(dǎo)出的變量,函數(shù),類,接口等的時(shí)候,你必須要導(dǎo)入它們,可以使用 import形式之一。
模塊是自聲明的;兩個(gè)模塊之間的關(guān)系是通過在文件級別上使用imports和exports建立的。
模塊使用模塊加載器去導(dǎo)入其它的模塊。 在運(yùn)行時(shí),模塊加載器的作用是在執(zhí)行此模塊代碼前去查找并執(zhí)行這個(gè)模塊的所有依賴。 大家最熟知的JavaScript模塊加載器是服務(wù)于Node.js的 CommonJS和服務(wù)于Web應(yīng)用的Require.js。
TypeScript與ECMAScript 2015一樣,任何包含頂級import或者export的文件都被當(dāng)成一個(gè)模塊。相反地,如果一個(gè)文件不帶有頂級的import或者export聲明,那么它的內(nèi)容被視為全局可見的(因此對模塊也是可見的)。
導(dǎo)出
導(dǎo)出聲明
任何聲明(比如變量,函數(shù),類,類型別名或接口)都能夠通過添加export關(guān)鍵字來導(dǎo)出。
Validation.ts
export interface StringValidator {
? ? isAcceptable(s: string): boolean;
}
ZipCodeValidator.ts
export const numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
? ? isAcceptable(s: string) {
? ? ? ? return s.length === 5 && numberRegexp.test(s);
? ? }
}
導(dǎo)出語句
導(dǎo)出語句很便利,因?yàn)槲覀兛赡苄枰獙?dǎo)出的部分重命名,所以上面的例子可以這樣改寫:
class ZipCodeValidator implements StringValidator {
? ? isAcceptable(s: string) {
? ? ? ? return s.length === 5 && numberRegexp.test(s);
? ? }
}
export { ZipCodeValidator };
export { ZipCodeValidator as mainValidator };
重新導(dǎo)出
我們經(jīng)常會(huì)去擴(kuò)展其它模塊,并且只導(dǎo)出那個(gè)模塊的部分內(nèi)容。 重新導(dǎo)出功能并不會(huì)在當(dāng)前模塊導(dǎo)入那個(gè)模塊或定義一個(gè)新的局部變量。
ParseIntBasedZipCodeValidator.ts
export class ParseIntBasedZipCodeValidator {
? ? isAcceptable(s: string) {
? ? ? ? return s.length === 5 && parseInt(s).toString() === s;
? ? }
}
// 導(dǎo)出原先的驗(yàn)證器但做了重命名
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
或者一個(gè)模塊可以包裹多個(gè)模塊,并把他們導(dǎo)出的內(nèi)容聯(lián)合在一起通過語法:export * from "module"。
AllValidators.ts
export * from "./StringValidator"; // exports interface StringValidator
export * from "./LettersOnlyValidator"; // exports class LettersOnlyValidator
export * from "./ZipCodeValidator";? // exports class ZipCodeValidator
導(dǎo)入
模塊的導(dǎo)入操作與導(dǎo)出一樣簡單。 可以使用以下 import形式之一來導(dǎo)入其它模塊中的導(dǎo)出內(nèi)容。
導(dǎo)入一個(gè)模塊中的某個(gè)導(dǎo)出內(nèi)容
import { ZipCodeValidator } from "./ZipCodeValidator";
let myValidator = new ZipCodeValidator();
可以對導(dǎo)入內(nèi)容重命名
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator = new ZCV();
將整個(gè)模塊導(dǎo)入到一個(gè)變量,并通過它來訪問模塊的導(dǎo)出部分
import * as validator from "./ZipCodeValidator";
let myValidator = new validator.ZipCodeValidator();
具有副作用的導(dǎo)入模塊
盡管不推薦這么做,一些模塊會(huì)設(shè)置一些全局狀態(tài)供其它模塊使用。 這些模塊可能沒有任何的導(dǎo)出或用戶根本就不關(guān)注它的導(dǎo)出。 使用下面的方法來導(dǎo)入這類模塊:
import "./my-module.js";
默認(rèn)導(dǎo)出
每個(gè)模塊都可以有一個(gè)default導(dǎo)出。 默認(rèn)導(dǎo)出使用 default關(guān)鍵字標(biāo)記;并且一個(gè)模塊只能夠有一個(gè)default導(dǎo)出。 需要使用一種特殊的導(dǎo)入形式來導(dǎo)入 default導(dǎo)出。
default導(dǎo)出十分便利。 比如,像JQuery這樣的類庫可能有一個(gè)默認(rèn)導(dǎo)出 jQuery或$,并且我們基本上也會(huì)使用同樣的名字jQuery或$導(dǎo)出JQuery。
JQuery.d.ts
declare let $: JQuery;
export default $;
App.ts
import $ from "JQuery";
$("button.continue").html( "Next Step..." );
類和函數(shù)聲明可以直接被標(biāo)記為默認(rèn)導(dǎo)出。 標(biāo)記為默認(rèn)導(dǎo)出的類和函數(shù)的名字是可以省略的。
ZipCodeValidator.ts
export default class ZipCodeValidator {
? ? static numberRegexp = /^[0-9]+$/;
? ? isAcceptable(s: string) {
? ? ? ? return s.length === 5 && ZipCodeValidator.numberRegexp.test(s);
? ? }
}
Test.ts
import validator from "./ZipCodeValidator";
let myValidator = new validator();
或者
StaticZipCodeValidator.ts
const numberRegexp = /^[0-9]+$/;
export default function (s: string) {
? ? return s.length === 5 && numberRegexp.test(s);
}
Test.ts
import validate from "./StaticZipCodeValidator";
let strings = ["Hello", "98052", "101"];
// Use function validate
strings.forEach(s => {
? console.log(`"${s}" ${validate(s) ? " matches" : " does not match"}`);
});
default導(dǎo)出也可以是一個(gè)值
OneTwoThree.ts
export default "123";
Log.ts
import num from "./OneTwoThree";
console.log(num); // "123"
export = 和 import = require()
CommonJS和AMD的環(huán)境里都有一個(gè)exports變量,這個(gè)變量包含了一個(gè)模塊的所有導(dǎo)出內(nèi)容。
CommonJS和AMD的exports都可以被賦值為一個(gè)對象, 這種情況下其作用就類似于 es6 語法里的默認(rèn)導(dǎo)出,即 export default語法了。雖然作用相似,但是 export default 語法并不能兼容CommonJS和AMD的exports。
為了支持CommonJS和AMD的exports, TypeScript提供了export =語法。
export =語法定義一個(gè)模塊的導(dǎo)出對象。 這里的對象一詞指的是類,接口,命名空間,函數(shù)或枚舉。
若使用export =導(dǎo)出一個(gè)模塊,則必須使用TypeScript的特定語法import module = require("module")來導(dǎo)入此模塊。
ZipCodeValidator.ts
let numberRegexp = /^[0-9]+$/;
class ZipCodeValidator {
? ? isAcceptable(s: string) {
? ? ? ? return s.length === 5 && numberRegexp.test(s);
? ? }
}
export = ZipCodeValidator;
Test.ts
import zip = require("./ZipCodeValidator");
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validator = new zip();
// Show whether each string passed each validator
strings.forEach(s => {
? console.log(`"${ s }" - ${ validator.isAcceptable(s) ? "matches" : "does not match" }`);
});
生成模塊代碼
根據(jù)編譯時(shí)指定的模塊目標(biāo)參數(shù),編譯器會(huì)生成相應(yīng)的供Node.js (CommonJS),Require.js (AMD),UMD,SystemJS或ECMAScript 2015 native modules (ES6)模塊加載系統(tǒng)使用的代碼。 想要了解生成代碼中 define,require 和 register的意義,請參考相應(yīng)模塊加載器的文檔。
下面的例子說明了導(dǎo)入導(dǎo)出語句里使用的名字是怎么轉(zhuǎn)換為相應(yīng)的模塊加載器代碼的。
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" && typeof module.exports === "object") {
? ? ? ? let v = factory(require, exports); if (v !== undefined) module.exports = 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
System.register(["./mod"], function(exports_1) {
? ? 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;