本篇將介紹TypeScript里的模塊,和使用方法。
在ECMAScript 2015標准里,JavaScript新增了模塊的概念。TypeScript也沿用了這個概念。
一、模塊的導入和導出
模塊在其自身的作用域里執行,而不是在全局作用域里;這意味着定義在一個模塊里的變量,函數,類等等在模塊外部是不可見的,除非你明確地使用export之一導出它們。 相反,如果想使用其它模塊導出的變量,函數,類,接口等的時候,你必須要導入它們,可以使用import之一。
模塊是自聲明的。在TypeScript里,兩個模塊之間的關系是通過在文件級別上使用import和export建立的。下面是一個基本例子:
animal.ts
1 export class Animal { 2 name: string; 3 show(): string { 4 return this.name; 5 } 6 }
app.ts
1 import {Animal} from './animal'; 2 let dog = new Animal(); 3 dog.name = '狗狗'; 4 dog.show();
上面的例子里,在animal.ts里聲明了一個類Animal,通過export導出。在app.ts里,指定相對文件路徑,通過import導入,就可以使用Animal類。
因為JavaScript存在兩種不同的模塊引用方式,在編譯成JavaScript時,可以通過TypeScript配置文件tsconfig.json指定編譯之后的模塊引用方式
1 { 2 "compilerOptions": { 3 "target": "es5", 4 "noImplicitAny": false, 5 "module": "commonjs", // 模塊引用方式。候選值有:commonjs、amd等 6 "removeComments": false, 7 "sourceMap": false, 8 "outDir": "js" 9 }, 10 "include":[ 11 "ts" 12 ], 13 "exclude": [ 14 "js" 15 ] 16 }
下面分別是使用不同的方式編譯后的JavaScript文件內容
commonjs
1 "use strict"; 2 var Animal = (function () { 3 function Animal() { 4 } 5 Animal.prototype.show = function () { 6 return this.name; 7 }; 8 return Animal; 9 }()); 10 exports.Animal = Animal;
1 'use strict'; 2 var animal_1 = require('./animal'); 3 var dog = new animal_1.Animal(); 4 dog.name = '狗狗'; 5 dog.show();
amd
1 define(["require", "exports"], function (require, exports) { 2 "use strict"; 3 var Animal = (function () { 4 function Animal() { 5 } 6 Animal.prototype.show = function () { 7 return this.name; 8 }; 9 return Animal; 10 }()); 11 exports.Animal = Animal; 12 });
1 define(["require", "exports", './animal'], function (require, exports, animal_1) { 2 'use strict'; 3 var dog = new animal_1.Animal(); 4 dog.name = '狗狗'; 5 dog.show(); 6 });
二、導入和導出的重命名
模塊導入和導出時默認使用的內部對象的名稱。TypeScript也支持在導出前和導入后進行重命名。將上面的例子修改一下
animal.ts
1 class Animal { 2 name: string; 3 show(): string { 4 return this.name; 5 } 6 } 7 8 export {Animal as ANI};
app.ts
1 import {ANI as Animal} from './animal'; 2 let dog = new Animal(); 3 dog.name = '狗狗'; 4 dog.show();
導入和導出時,通過as關鍵字對模塊進行重命名。
這個地方有一點要注意,當導出的模塊重命名后,導入時重命名前的模塊名要與導出重命名后的模塊名保持一致,否則編譯器將提示錯誤信息。以上面的這個例子為例,導出的模塊被重命名為ANI,將此模塊在另外一個文件app.ts里導入時,as關鍵字前面的模塊名必須是ANI。
或者,如果不知道導入模塊的名稱,則可以用*號代替
1 import * as animal_module from './animal'; 2 let dog = new animal_module.ANI(); 3 dog.name = '狗狗'; 4 dog.show();
上面的例子里,對*號代替的所有模塊進行重命名為animal_module,則通過animal_module對象可以訪問到模塊里導出的所有內容。
三、導出和導出多個對象
通常情況,模塊里會定義多個類型對象,然后一並導出。而導入的模塊里也可能會有多個
animal.ts
1 enum HairColor { 2 Golden, 3 Black, 4 White 5 } 6 7 class Animal { 8 name: string; 9 color: HairColor; 10 show(): string { 11 return this.name; 12 } 13 } 14 15 export {Animal, HairColor};
app.ts
1 import * as animal_module from './animal'; 2 let dog = new animal_module.Animal(); 3 dog.name = '狗狗'; 4 dog.color = animal_module.HairColor.Golden; 5 dog.show();
導出時,可以將要導出的類型對象重新組裝成一個json對象,然后導出。導入后,可以通過重命名的模塊對象訪問里面的內容。
四、默認導出
一個模塊的默認導出只能有一個
animal.ts
1 class Animal { 2 name: string; 3 show(): string { 4 return this.name; 5 } 6 } 7 8 export default Animal;
app.ts
1 import Animal from './animal'; 2 let dog = new Animal(); 3 dog.name = '狗狗'; 4 dog.show();
在上面的例子里,通過default關鍵字,將Animal類導出。與一般的導入不同的是,導入默認的導出模塊時,可以直接指定導入的模塊名稱,而不需要用{}花括號括起來。
五、動態加載模塊
因為在JavaScript里,模塊加載方式分別有兩種:CommonJS和AMD。在用TypeScript時,要根據最終編譯生成JavaScript的方式的配置內容不同,編寫不同的代碼。
模塊文件animal.ts
1 class Animal { 2 name: string; 3 show(): string { 4 return this.name; 5 } 6 } 7 8 export {Animal};
CommonJS方式引用:
app.ts
1 // 定義加載方法 2 declare function require(moduleName: string): any; 3 4 import {Animal} from './animal'; 5 6 if (true) { 7 let Animal_Type: typeof Animal = require('./animal'); 8 let dog = new Animal_Type(); 9 dog.name = '狗狗'; 10 dog.show(); 11 }
AMD方式引用:
app.ts
1 // 定義加載方法 2 declare function require(moduleNames: string[], onLoad: (...args: any[]) => void): void; 3 4 import {Animal} from './animal'; 5 6 if (true) { 7 require(["./animal"], (Animal_Type: typeof Animal) => { 8 let dog = new Animal_Type(); 9 dog.name = '狗狗'; 10 dog.show(); 11 }); 12 }
