TypeScript 命名空間和模塊

2022-04-21 09:24 更新

關(guān)于術(shù)語的一點說明: 請務(wù)必注意一點,TypeScript 1.5里術(shù)語名已經(jīng)發(fā)生了變化。 “內(nèi)部模塊”現(xiàn)在稱做“命名空間”。 “外部模塊”現(xiàn)在則簡稱為“模塊”,這是為了與 ECMAScript 2015里的術(shù)語保持一致,(也就是說module X {相當于現(xiàn)在推薦的寫法 namespace X {)。

介紹

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

查看模塊章節(jié)了解關(guān)于模塊的更多信息。 查看 命名空間章節(jié)了解關(guān)于命名空間的更多信息。

使用命名空間

命名空間是位于全局命名空間下的一個普通的帶有名字的JavaScript對象。 這令命名空間十分容易使用。 它們可以在多文件中同時使用,并通過 --outFile結(jié)合在一起。 命名空間是幫你組織Web應(yīng)用不錯的方式,你可以把所有依賴都放在HTML頁面的 <script>標簽里。

但就像其它的全局命名空間污染一樣,它很難去識別組件之間的依賴關(guān)系,尤其是在大型的應(yīng)用中。

使用模塊

像命名空間一樣,模塊可以包含代碼和聲明。 不同的是模塊可以 聲明它的依賴。

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

對于Node.js應(yīng)用來說,模塊是默認并推薦的組織代碼的方式。

從ECMAScript 2015開始,模塊成為了語言內(nèi)置的部分,應(yīng)該會被所有正常的解釋引擎所支持。 因此,對于新項目來說推薦使用模塊做為組織代碼的方式。

命名空間和模塊的陷阱

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

對模塊使用/// <reference>

一個常見的錯誤是使用/// <reference>引用模塊文件,應(yīng)該使用import。 要理解這之間的區(qū)別,我們首先應(yīng)該弄清編譯器是如何根據(jù) import路徑(例如,import x from "...";import x = require("...")里面的...,等等)來定位模塊的類型信息的。

編譯器首先嘗試去查找相應(yīng)路徑下的.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的方法。

不必要的命名空間

如果你想把命名空間轉(zhuǎn)換為模塊,它可能會像下面這個文件一件:

  • 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里模塊的一個特點是不同的模塊永遠也不會在相同的作用域內(nèi)使用相同的名字。 因為使用模塊的人會為它們命名,所以完全沒有必要把導(dǎo)出的符號包裹在一個命名空間里。

再次重申,不應(yīng)該對模塊使用命名空間,使用命名空間是為了提供邏輯分組和避免命名沖突。 模塊文件本身已經(jīng)是一個邏輯分組,并且它的名字是由導(dǎo)入這個模塊的代碼指定,所以沒有必要為導(dǎo)出的對象增加額外的模塊層。

下面是改進的例子:

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

模塊的取舍

就像每個JS文件對應(yīng)一個模塊一樣,TypeScript里模塊文件與生成的JS文件也是一一對應(yīng)的。 這會產(chǎn)生一種影響,根據(jù)你指定的目標模塊系統(tǒng)的不同,你可能無法連接多個模塊源文件。 例如當目標模塊系統(tǒng)為 commonjsumd時,無法使用outFile選項,但是在TypeScript 1.8以上的版本能夠使用outFile當目標為amdsystem。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號