TypeScript 模塊
在沒有使用模塊化編程的時代,會經常遇到全局變量污染、變量重名、多個文件之間存在依賴關系,需要保證一定加載順序等問題。在模塊化這種規范被提出后,得到社區和廣大開發者的積極響應。
本節將介紹 TypeScript 的模塊化方案,學習模塊的導入導出機制,要注意 TypeScript 是怎么樣兼容 CommonJS 和 AMD 規范的。
1. 慕課解釋
模塊在其自身的作用域里執行,而不是在全局作用域里。
export
: 導出模塊中的變量、函數、類、接口等;
import
: 導入其他模塊導出的變量、函數、類、接口等。
TypeScript 與 ECMAScript 2015 一樣,任何包含頂級 import
或者 export
的文件都被當成一個模塊。相反的,如果一個文件不帶有頂級的 import
或者 export
聲明,那么它的內容被視為全局可見的。
2. 全局模塊
在一個 TypeScript 工程創建一個 test.ts
文件,寫入代碼:
const a = 1
然后,在相同的工程下創建另一個 test2.ts
文件,寫入代碼:
const a = 2
此時編譯器會提示重復定義錯誤,雖然是在不同的文件下,但處于同一全局空間。
如果加上 export
導出語句:
export const a = 1
這樣,兩個 a
因處于不同的命名空間,就不會報錯。
3. 導出語法
3.1 使用 export 導出聲明
任何聲明(比如變量,函數,類,類型別名或接口)都能夠通過添加 export
關鍵字來導出。
export.ts
:
export const a: number = 1
export const add = (x: number, y:number) => x + y
export interface User {
nickname: string,
department: string
}
export class Employee implements User {
public nickname!: string
public department!: string
}
export type used = true | false
解釋: 每個聲明都通過 export
關鍵字導出。
3.2 先聲明,后導出
const a: number = 1
const add = (x: number, y:number) => x + y
interface User {
nickname: string,
department: string
}
class Employee implements User {
public nickname!: string
public department!: string
}
type used = true | false
export { a, add, Employee }
解釋: 先進行聲明操作,最終統一使用 export
關鍵字導出。
3.3 導出時重命名
const a: number = 1
const add = (x: number, y:number) => x + y
interface User {
nickname: string,
department: string
}
class Employee implements User {
public nickname!: string
public department!: string
}
type used = true | false
export { add }
export { a as level, used as status, Employee }
解釋: 在導出時,可以用 as
關鍵字將聲明重命名。
3.4 重新導出
重新導出功能并不會在當前模塊導入那個模塊或定義一個新的局部變量。
ZipCodeValidator.ts
:
export interface StringValidator {
isAcceptable(s: string): boolean
}
export const numberRegexp = /^[0-9]+$/
class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s)
}
}
export { ZipCodeValidator }
export { ZipCodeValidator as mainValidator }
ParseIntBasedZipCodeValidator.ts
:
export class ParseIntBasedZipCodeValidator {
isAcceptable(s: string) {
return s.length === 5 && parseInt(s).toString() === s
}
}
// 導出原先的驗證器但做了重命名
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from './ZipCodeValidator'
代碼解釋: 在 ParseIntBasedZipCodeValidator.ts 文件中,重新導出 ZipCodeValidator.ts 文件中的聲明。
或者一個模塊可以包裹多個模塊,并把他們導出的內容聯合在一起通過語法:export * from 'module'
。
比如在 validator.ts
文件中,統一導出這兩個模塊。
// validator.ts
export * from './ZipCodeValidator'
export * from './ParseIntBasedZipCodeValidator'
3.5 默認導出
export default class ZipCodeValidator {
static numberRegexp = /^[0-9]+$/
isAcceptable(s: string) {
return s.length === 5 && ZipCodeValidator.numberRegexp.test(s)
}
}
代碼解釋: 每個模塊都可以有一個 default
導出,且一個模塊只能夠有一個 default
導出。
4. 導入語法
4.1 使用 import 導入
使用 import
形式來導入其它模塊中的導出內容。
import { a, add, Employee } from './export'
4.2 導入時重命名
import { a as level, used as status } from './export'
4.3 將整個模塊導入到一個變量
將整個模塊導入到一個變量,并通過它來訪問模塊的導出部分
import * as TYPES from './export'
4.4 直接導入
import './export'
5. export =
和 import = require()
CommonJS 和 AMD 的環境里都有一個 exports
變量,這個變量包含了一個模塊的所有導出內容。
CommonJS 和 AMD 的 exports
都可以被賦值為一個 對象
, 這種情況下其作用就類似于 EcmaScript 2015 語法里的默認導出,即 export default
語法了。雖然作用相似,但是 export default
語法并不能兼容 CommonJS 和 AMD 的 exports
。
為了支持 CommonJS 和 AMD 的 exports, TypeScript 提供了 export =
語法。
export =
語法定義一個模塊的導出 對象
。 這里的 對象
一詞指的是類,接口,命名空間,函數或枚舉。
若使用 export =
導出一個模塊,則必須使用 TypeScript 的特定語法 import module = require('module')
來導入此模塊。
export =
只能導出對象
export =
導出的模塊只能用import = require()
形式導入
文件 ZipCodeValidator.ts
:
let numberRegexp = /^[0-9]+$/
class ZipCodeValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s)
}
}
export = ZipCodeValidator
代碼解釋: 使用 export = 語法導出一個類對象。
文件 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' }`)
});
代碼解釋: 通過 import = require()
形式導入。
6. 小結
可以看到 TypeScript 的模塊機制基本采用的是 ES6 的內置模塊化機制,另外添加了 export =
形式來兼容 AMD 與 CommonJS 規范。