1. 程式人生 > 實用技巧 >TypeScript名稱空間和模組

TypeScript名稱空間和模組

關於術語的一點說明: 請務必注意一點,TypeScript 1.5裡術語名已經發生了變化。 “內部模組”現在稱做“名稱空間”。 “外部模組”現在則簡稱為“模組”,這是為了與 ECMAScript 2015裡的術語保持一致,(也就是說 module X { 相當於現在推薦的寫法 namespace X {)。

介紹

這篇文章將概括介紹在TypeScript裡使用模組與名稱空間來組織程式碼的方法。 我們也會談及名稱空間和模組的高階使用場景,和在使用它們的過程中常見的陷阱。

檢視模組章節瞭解關於模組的更多資訊。 檢視 名稱空間章節瞭解關於名稱空間的更多資訊。

使用名稱空間

名稱空間是位於全域性名稱空間下的一個普通的帶有名字的JavaScript物件。 這令名稱空間十分容易使用。 它們可以在多檔案中同時使用,並通過 --outFile

結合在一起。 名稱空間是幫你組織Web應用不錯的方式,你可以把所有依賴都放在HTML頁面的 ``標籤裡。

但就像其它的全域性名稱空間汙染一樣,它很難去識別元件之間的依賴關係,尤其是在大型的應用中。

使用模組

像名稱空間一樣,模組可以包含程式碼和宣告。 不同的是模組可以 宣告它的依賴。

模組會把依賴新增到模組載入器上(例如CommonJs / Require.js)。 對於小型的JS應用來說可能沒必要,但是對於大型應用,這一點點的花費會帶來長久的模組化和可維護性上的便利。 模組也提供了更好的程式碼重用,更強的封閉性以及更好的使用工具進行優化。

對於Node.js應用來說,模組是預設並推薦的組織程式碼的方式。

從ECMAScript 2015開始,模組成為了語言內建的部分,應該會被所有正常的解釋引擎所支援。 因此,對於新專案來說推薦使用模組做為組織程式碼的方式。

名稱空間和模組的陷阱

這部分我們會描述常見的名稱空間和模組的使用陷阱和如何去避免它們。

對模組使用///

一個常見的錯誤是使用/// 引用模組檔案,應該使用import。 要理解這之間的區別,我們首先應該弄清編譯器是如何根據 import路徑(例如,import x from "...";import x = require("...")裡面的...,等等)來定位模組的型別資訊的。

編譯器首先嚐試去查詢相應路徑下的.ts.tsx再或者.d.ts。 如果這些檔案都找不到,編譯器會查詢 外部模組宣告

。 回想一下,它們是在 .d.ts檔案裡宣告的。

  • myModules.d.ts
// In a .d.ts file or .ts file that is not a module:
declare module "SomeModule" {
    export function fn(): string;
}
  • myOtherModule.ts
/// <reference path="myModules.d.ts" />
import * as m from "SomeModule";

這裡的引用標籤指定了外來模組的位置。 這就是一些TypeScript例子中引用 node.d.ts的方法。

不必要的名稱空間

如果你想把名稱空間轉換為模組,它可能會像下面這個檔案一件:

  • shapes.ts
export namespace Shapes {
    export class Triangle { /* ... */ }
    export class Square { /* ... */ }
}

頂層的模組Shapes包裹了TriangleSquare。 對於使用它的人來說這是令人迷惑和討厭的:

  • shapeConsumer.ts
import * as shapes from "./shapes";
let t = new shapes.Shapes.Triangle(); // shapes.Shapes?

TypeScript裡模組的一個特點是不同的模組永遠也不會在相同的作用域內使用相同的名字。 因為使用模組的人會為它們命名,所以完全沒有必要把匯出的符號包裹在一個名稱空間裡。

再次重申,不應該對模組使用名稱空間,使用名稱空間是為了提供邏輯分組和避免命名衝突。 模組檔案本身已經是一個邏輯分組,並且它的名字是由匯入這個模組的程式碼指定,所以沒有必要為匯出的物件增加額外的模組層。

下面是改進的例子:

  • shapes.ts
export class Triangle { /* ... */ }
export class Square { /* ... */ }
  • shapeConsumer.ts
import * as shapes from "./shapes";
let t = new shapes.Triangle();

模組的取捨

就像每個JS檔案對應一個模組一樣,TypeScript裡模組檔案與生成的JS檔案也是一一對應的。 這會產生一種影響,根據你指定的目標模組系統的不同,你可能無法連線多個模組原始檔。 例如當目標模組系統為 commonjsumd時,無法使用outFile選項,但是在TypeScript 1.8以上的版本能夠使用outFile當目標為amdsystem