TypeScript 也支援 ES6 的 module

ES6 提出了 module 概念,讓我們將程式碼加以模組化,避免如 ES5 一樣常常寫出幾千行的程式碼,造成日後難以維護,TypeScript 也支援 ES6 的 module。

Version


TypeScrpit 2.3

Introduction


Module 有自己的 scope,不是 global scope,也就是說,在 module 內的變數、function、class 與 interface …,只有在同一個 module 內才看得到,除非特別加上 export 關鍵字,外界才能存取;同樣的,module 要使用其他 module 的變數、function、class 與 interface …,除非特別加上 import 關鍵字,才能存取外界。

在 TypeScript,只要檔案中存在 importexport 關鍵字,都被視為 module。

Export


直接 Export

Validation.ts

1
2
3
export interface StringValidator {
isAcceptable(s: string): boolean;
}

interface 前面加上 export,則可直接 export 出去。

ZipCodeValidator.ts

1
2
3
4
5
6
7
export const numberRegexp = /^[0-9]+$/;

export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}

const 之前加上 export,則可直接 export 出去。

class 之前加上 export ,則可直接 export 出去。

要直接 export,只要在 constfunctionclassinterface 之前加上 export 關鍵字即可。

以別名 Export

1
2
3
4
5
6
7
class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
export { ZipCodeValidator };
export { ZipCodeValidator as mainValidator };

第 6 行

1
export { ZipCodeValidator };

相當於

1
2
3
4
5
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}

第 7 行

1
export { ZipCodeValidator as mainValidator };

將原本 ZipCodeValidatormainValidator 名稱 export 出去。

實務上有可能原本要 export 的名稱太長,或者不夠貼近 domain,因此不適合使用者,需要用更簡短、更精準的名稱時,可以搭配 as

重新 Export

ParseIntBasedZipCodeValidator.ts

1
2
3
4
5
6
7
8
export class ParseIntBasedZipCodeValidator {
isAcceptable(s: string) {
return s.length === 5 && parseInt(s).toString() === s;
}
}

// Export original validator but rename it
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";

使用 export {} from 可以從另外一個 module 間接的將另外一個 module 內的東西 export 出去。

可明確指定要 export 什麼東西。

AllValidators.ts

1
2
3
export * from "./StringValidator"; // exports interface 'StringValidator'
export * from "./LettersOnlyValidator"; // exports class 'LettersOnlyValidator'
export * from "./ZipCodeValidator"; // exports class 'ZipCodeValidator'

使用 export * from 明確另外一個 module 的所有東西 export 出去。

Import


單一 Import

1
2
import { ZipCodeValidator } from "./ZipCodeValidator";
let myValidator = new ZipCodeValidator();

使用 import {} from 可以從一個 module 單一 import 一個東西。

以別名 Import

1
2
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator = new ZCV();

使用 import { as } from 可以從一個 module 單一 import 後,並同時取別名。

1
2
import * as validator from "./ZipCodeValidator";
let myValidator = new validator.ZipCodeValidator();

使用 import * as from 將一個 module 所有東西 import 成一個變數,並透過變數去存取所有 export 的東西。

Default Export


一個 module 僅可以有一個 default export。

ZipCodeValidator.ts

1
2
3
4
5
6
export default class ZipCodeValidator {
static numberRegexp = /^[0-9]+$/;
isAcceptable(s: string) {
return s.length === 5 && ZipCodeValidator.numberRegexp.test(s);
}
}

export 之後加上 default

Test.ts

1
2
import validator from "./ZipCodeValidator";
let myValidator = new validator();

使用 import 名稱 from,不需使用 {},直接將 default export 成特定名稱。

Conclusion


  • 透過 module,我們能將功能相近的變數、function、class 與 interface 放在同一個 module,讓程式碼更加模組化,避免一個檔案好幾千行而難以維護。

Reference


TypeScript, Handbook : Modules

2017-06-18