TypeScript 命名空間和模塊

2022-04-21 09:24 更新

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

介紹

這篇文章將概括介紹在TypeScript里使用模塊與命名空間來(lái)組織代碼的方法。 我們也會(huì)談及命名空間和模塊的高級(jí)使用場(chǎng)景,和在使用它們的過(guò)程中常見(jiàn)的陷阱。

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

使用命名空間

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

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

使用模塊

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

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

對(duì)于Node.js應(yīng)用來(lái)說(shuō),模塊是默認(rèn)并推薦的組織代碼的方式。

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

命名空間和模塊的陷阱

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

對(duì)模塊使用/// <reference>

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

編譯器首先嘗試去查找相應(yīng)路徑下的.ts.tsx再或者.d.ts。 如果這些文件都找不到,編譯器會(huì)查找 外部模塊聲明。 回想一下,它們是在 .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";

這里的引用標(biāo)簽指定了外來(lái)模塊的位置。 這就是一些Typescript例子中引用 node.d.ts的方法。

不必要的命名空間

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

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

頂層的模塊Shapes包裹了TriangleSquare。 對(duì)于使用它的人來(lái)說(shuō)這是令人迷惑和討厭的:

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

TypeScript里模塊的一個(gè)特點(diǎn)是不同的模塊永遠(yuǎn)也不會(huì)在相同的作用域內(nèi)使用相同的名字。 因?yàn)槭褂媚K的人會(huì)為它們命名,所以完全沒(méi)有必要把導(dǎo)出的符號(hào)包裹在一個(gè)命名空間里。

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

下面是改進(jìn)的例子:

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

模塊的取舍

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


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)