鍍金池/ 教程/ HTML/ 介紹
初始化項(xiàng)目結(jié)構(gòu)
聯(lián)合類型
介紹
介紹
介紹
編譯選項(xiàng)
TypeScript 1.6
介紹
介紹
發(fā)展路線圖
介紹
在MSBuild里使用編譯選項(xiàng)
可迭代性
TypeScript 1.3
介紹
介紹
TypeScript 1.1
變量聲明
即將到來的Angular 2框架是使用TypeScript開發(fā)的。 因此Angular和TypeScript一起使用非常簡單方便
tsconfig.json
介紹
介紹
介紹
在MSBuild里使用編譯選項(xiàng)
使用TypeScript的每日構(gòu)建版本
新建工程
枚舉
三斜線指令
結(jié)合ASP.NET v5使用TypeScript
TypeScript里的this
介紹
TypeScript 1.4
編碼規(guī)范
介紹
模塊解析
ASP.NET 4
架構(gòu)概述
介紹
介紹
ASP.NET Core
TypeScript 1.8
介紹
介紹
創(chuàng)建簡單工程
TypeScript 1.7
TypeScript 1.5
NPM包的類型
支持TypeScript的編輯器

介紹

這篇文章描述了如何在TypeScript里使用命名空間(之前叫做“內(nèi)部模塊”)來組織你的代碼。

就像我們?cè)谛g(shù)語說明里提到的那樣,“內(nèi)部模塊”現(xiàn)在叫做“命名空間”。

另外,任何使用module關(guān)鍵字來聲明一個(gè)內(nèi)部模塊的地方都應(yīng)該使用namespace關(guān)鍵字來替換。

這就避免了讓新的使用者被相似的名稱所迷惑。

第一步

我們先來寫一段程序并將在整篇文章中都使用這個(gè)例子。 我們定義幾個(gè)簡單的字符串驗(yàn)證器,假設(shè)你會(huì)使用它們來驗(yàn)證表單里的用戶輸入或驗(yàn)證外部數(shù)據(jù)。

所有的驗(yàn)證器都放在一個(gè)文件里

interface StringValidator {
    isAcceptable(s: string): boolean;
}

let lettersRegexp = /^[A-Za-z]+$/;
let numberRegexp = /^[0-9]+$/;

class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}

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

// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: StringValidator; } = {};
validators["ZIP code"] = new ZipCodeValidator();
validators["Letters only"] = new LettersOnlyValidator();
// Show whether each string passed each validator
strings.forEach(s => {
    for (let name in validators) {
        console.log(""" + s + "" " + (validators[name].isAcceptable(s) ? " matches " : " does not match ") + name);
    }
});

命名空間

隨著更多驗(yàn)證器的加入,我們需要一種手段來組織代碼,以便于在記錄它們類型的同時(shí)還不用擔(dān)心與其它對(duì)象產(chǎn)生命名沖突。 因此,我們把驗(yàn)證器包裹到一個(gè)命名空間內(nèi),而不是把它們放在全局命名空間下。

下面的例子里,把所有與驗(yàn)證器相關(guān)的類型都放到一個(gè)叫做Validation的命名空間里。 因?yàn)槲覀兿胱屵@些接口和類在命名空間之外也是可訪問的,所以需要使用export。 相反的,變量lettersRegexpnumberRegexp是實(shí)現(xiàn)的細(xì)節(jié),不需要導(dǎo)出,因此它們?cè)诿臻g外是不能訪問的。 在文件末尾的測試代碼里,由于是在命名空間之外訪問,因此需要限定類型的名稱,比如Validation.LettersOnlyValidator。

使用命名空間的驗(yàn)證器

namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }

    const lettersRegexp = /^[A-Za-z]+$/;
    const numberRegexp = /^[0-9]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }

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

// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
strings.forEach(s => {
    for (let name in validators) {
        console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
    }
});

分離到多文件

當(dāng)應(yīng)用變得越來越大時(shí),我們需要將代碼分離到不同的文件中以便于維護(hù)。

多文件中的命名空間

現(xiàn)在,我們把Validation命名空間分割成多個(gè)文件。 盡管是不同的文件,它們?nèi)允峭粋€(gè)命名空間,并且在使用的時(shí)候就如同它們?cè)谝粋€(gè)文件中定義的一樣。 因?yàn)椴煌募g存在依賴關(guān)系,所以我們加入了引用標(biāo)簽來告訴編譯器文件之間的關(guān)聯(lián)。 我們的測試代碼保持不變。

Validation.ts
namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}
LettersOnlyValidator.ts
/// <reference path="Validation.ts" />
namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}
ZipCodeValidator.ts
/// <reference path="Validation.ts" />
namespace Validation {
    const numberRegexp = /^[0-9]+$/;
    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}
Test.ts
/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />
/// <reference path="ZipCodeValidator.ts" />

// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
strings.forEach(s => {
    for (let name in validators) {
        console.log(""" + s + "" " + (validators[name].isAcceptable(s) ? " matches " : " does not match ") + name);
    }
});

當(dāng)涉及到多文件時(shí),我們必須確保所有編譯后的代碼都被加載了。 我們有兩種方式。

第一種方式,把所有的輸入文件編譯為一個(gè)輸出文件,需要使用--outFile標(biāo)記:

tsc --outFile sample.js Test.ts

編譯器會(huì)根據(jù)源碼里的引用標(biāo)簽自動(dòng)地對(duì)輸出進(jìn)行排序。你也可以單獨(dú)地指定每個(gè)文件。

tsc --outFile sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts

第二種方式,我們可以編譯每一個(gè)文件(默認(rèn)方式),那么每個(gè)源文件都會(huì)對(duì)應(yīng)生成一個(gè)JavaScript文件。 然后,在頁面上通過<script>標(biāo)簽把所有生成的JavaScript文件按正確的順序引進(jìn)來,比如:

MyTestPage.html (excerpt)
    <script src="Validation.js" type="text/javascript" />
    <script src="LettersOnlyValidator.js" type="text/javascript" />
    <script src="ZipCodeValidator.js" type="text/javascript" />
    <script src="Test.js" type="text/javascript" />

別名

另一種簡化命名空間操作的方法是使用import q = x.y.z給常用的對(duì)象起一個(gè)短的名字。 不要與用來加載模塊的import x = require('name')語法弄混了,這里的語法是為指定的符號(hào)創(chuàng)建一個(gè)別名。 你可以用這種方法為任意標(biāo)識(shí)符創(chuàng)建別名,也包括導(dǎo)入的模塊中的對(duì)象。

namespace Shapes {
    export namespace Polygons {
        export class Triangle { }
        export class Square { }
    }
}

import polygons = Shapes.Polygons;
let sq = new polygons.Square(); // Same as "new Shapes.Polygons.Square()"

注意,我們并沒有使用require關(guān)鍵字,而是直接使用導(dǎo)入符號(hào)的限定名賦值。 這與使用var相似,但它還適用于類型和導(dǎo)入的具有命名空間含義的符號(hào)。 重要的是,對(duì)于值來講,import會(huì)生成與原始符號(hào)不同的引用,所以改變別名的var值并不會(huì)影響原始變量的值。

使用其它的JavaScript庫

為了描述不是用TypeScript編寫的類庫的類型,我們需要聲明類庫導(dǎo)出的API。 由于大部分程序庫只提供少數(shù)的頂級(jí)對(duì)象,命名空間是用來表示它們的一個(gè)好辦法。

我們稱其為聲明是因?yàn)樗皇峭獠砍绦虻木唧w實(shí)現(xiàn)。 我們通常在.d.ts里寫這些聲明。 如果你熟悉C/C++,你可以把它們當(dāng)做.h文件。 讓我們看一些例子。

外部命名空間

流行的程序庫D3在全局對(duì)象d3里定義它的功能。 因?yàn)檫@個(gè)庫通過一個(gè)<script>標(biāo)簽加載(不是通過模塊加載器),它的聲明文件使用內(nèi)部模塊來定義它的類型。 為了讓TypeScript編譯器識(shí)別它的類型,我們使用外部命名空間聲明。 比如,我們可以像下面這樣寫:

D3.d.ts (部分摘錄)
declare namespace D3 {
    export interface Selectors {
        select: {
            (selector: string): Selection;
            (element: EventTarget): Selection;
        };
    }

    export interface Event {
        x: number;
        y: number;
    }

    export interface Base extends Selectors {
        event: Event;
    }
}

declare let d3: D3.Base;
上一篇:變量聲明下一篇:介紹