[TS] Namespaces and Modules
TL;DR
// namespace import
import * as yup form 'yup';
// namespace re-export
export * from 'types/device';
export * as foo from 'types/device';
// re-export: make default-export becomes to named-export
export { default } from 'components/Card';
export { default as ResidentCard } from './ResidentCard';
// 只 import type 而非 value
import type { HasPhoneNumber } from '../typescript-fundamental-v2/1-basics';
// make file as modules
export {};
此篇為各筆記之整理,非原創內容,資料來源可見下方連結與文 後參考資料:
- Namespaces and Modules @ TypeScript
- Modules @ TypeScript
- Namespaces @ TypeScript
在 TypeScript 1.5 以後,原本的 internal modules 改名為 namespaces;原本的 external modules 改名為 modules。
在 TypeScript 中,只要檔案中有使用到 import
或 export
,則該檔案即會被視為 module;但若沒有,則會套用 TypeScript 中 namespaces 個概念,這將會導致不同檔案間同名稱的變數有衝突的情況。要解決這個問題,只需要在檔案的最上方加上 export {};
讓這支檔案被當成 module 來處理即可。
Modules
在 Modules 中可以同時包含程式碼(code)和宣告(declaration)。Modules 的使用需要依靠 module loader(例如,CommonJs/Require.js)或其他支援 ES Modules 的執行環境(runtime)。在當今的 Node.js 應用程式中,相較於 namespaces 的用法,modules 是更推薦的使用方式。
如同 ES6,在 TypeScript 中任何包含 import
或 export
的檔案都被視為 module,相反的若沒有使用到 import
或 export
則被視為 script,這裡面的變數會暴露在全域。
export interface StringValidator {
isAcceptable(s: string): boolean;
}
// 函式和 Class 的語法可以直接接在 `export default` 後而不需要特別命名。
export default function (s: string) {
return s.length === 5 && numberRegexp.test(s);
}
import type
在匯入型別(type)時,原本是使用 import
,在 TypeScript 3.8 之後,還可以使用 import type
語法:
// Explicitly use import type
import type { APIResponseType } from './api';
// Re-using the same import
import { APIResponseType } from './api';
default exports
使用 export default
匯出:
// pkg.ts
const foo = 'foo';
export default foo;
使用 import <name> from <path>
匯入:
// main.ts
import bar from './pkg';
console.log(bar); // foo
export = 和 import = require() 語法
在 TS 中還有一種特殊的 export =
和 import = require()
的用法,這兩種必須對應使用。這個用法通常適合用在下述的情況。
情境描述
由於 TypeScript 在預設情況下(esModuleInterop: false
),會有以下假設:
import * as moment from 'moment';
// 等同於
const moment = require('moment');
和
import moment from 'moment';
// 等同於
const moment = require('moment').default;
此時如果 JavaScript 的 library 是直接匯出一個函式:
function getMockPerson() {
return { firstName: 'aaron', lastName: 'Chen' };
}
// CJS 對應的寫法:
// module.exports = getMockPerson;
export = getMockPerson; // TS 中對應的寫法
若我們想要使用這個 library 時,會發生錯誤:
// namespace import 載入的內容會是物件
import * as getMockPerson from './getMockPerson';
// 會試圖去拿 getMockPerson.default,但這並不存在
import getMockPerson from './getMockPerson';
解決方式 1:使用 import = require() 語法
使用 export =
來匯出:
// getMockPerson.ts
function getMockPerson() {
return { firstName: 'aaron', lastName: 'Chen' };
}
// 等同於 CJS 中的:
// module.exports = getMockPerson;
export = getMockPerson;
使用 import <name> = require('<path>')
來匯入:
// main.ts
import getMockPerson = require('./getMockPerson');
console.log(getMockPerson());