做者: Angus.Fenying <i.am.x.fenying@gmail.com>node
日期: 2016-09-15 05:40 PM瀏覽器
咱們知道 NPM 包能夠有內建的 TS 聲明文件,從而免去使用 typings 工具安裝 TS 聲明文件的操做。那既然能夠有內建的聲明文件,爲什麼還須要額外安裝呢?由於不是 全部人都在使用 TypeScript,不少 NPM 模塊都是純 JavaScript 編寫的,其做者 沒有太大的可能性爲之編寫模塊聲明文件。並且內建的聲明文件有必定約束。app
TypeScript 的 DefinitelyTyped 聲明文件有兩種寫法,一種叫作 全局類型聲明(Global Type Definition),另外一個則是叫作 模塊導出聲明(External Module Definition)。函數
External Module 一詞源自 TypeScript 1.5 以前的 內部模塊/外部模塊 之說,而 1.5 以後內部模塊變成了 namespace,外部模塊直接化爲模塊, 再也不有內外部模塊之說。工具
因此這裏將
External Module Definition
譯爲模塊導出聲明
比較合適。ui
DefinitelyTyped 對此的說明是:spa
這二者有什麼不一樣呢?code
首先,最主要的區別在於,NPM 模塊裏面的內建聲明文件必須使用模塊導出聲明寫法, 不然 TypeScript 編譯沒法經過。下面來看一個簡單的例子:ip
以一個名爲 abc 的模塊爲例,TS源代碼以下:get
export function abc(s: string): string { return s.substr(0, 4); }
其聲明文件有兩種寫法:
第一種,模塊導出聲明寫法
declare interface funcAbcSign { (s: string): string } export declare let abc: funcAbcSign;
第二種,全局類型聲明寫法
declare module "abc" { interface funcAbcSign { (s: string): string } export let abc: funcAbcSign; }
若是要理解二者的區別,首先要理解其意義。模塊導出聲明寫法
中,單從這個文件內容 看來是沒法得知這些內容屬於哪一個模塊的。因此必須將之與模塊放在一塊兒,做爲內建聲明文件, TypeScript 編譯器才能得知其所屬的模塊。(或者放進 typings 的 external 目錄)
全局類型聲明寫法
中,其實是將模塊名稱 abc
引入了全局空間,即告訴 TypeScript 編譯器,存在一個叫 abc
的模塊,想使用裏面的名稱,就 import 吧!
由於任何一個 Node.js 的模塊都是必須依靠 require 加載的才能經過字段引用的方式 使用裏面的名稱,便是說 一個模塊沒法真正地將任何名稱引入全局的命名空間中,因此不該該也不能在一個模塊 的內建聲明文件裏使用全局聲明寫法!
這樣,就明白了何時應該使用全局聲明寫法,何時應該使用模塊導出聲明寫法了
若是你寫的 TypeScript 文件是在瀏覽器上經過 <script>
標籤加載的,那麼裏面的 變量、函數等都會被引入到全局命名空間中,這時候就須要爲這個文件寫一份全局類型聲明 了!好比這個文件:
// 定義了一個全局變量,整個頁面內均可見 let appStartedTime: Date = new Date();
你須要爲之寫一份 .d.ts
文件,供其它 ts 文件引用:
// 這裏將變量名 appStartedTime 引入了 TypeScript 的全局命名空間中。 declare let appStartedTime: Date;
除此以外,你能夠用一個全局類型聲明文件定義多個模塊、命名空間,例如:
// node.d.ts declare namespace NodeJS { export interface Error { "name": string; } } declare module "http" { // Node built-in module http } declare module "fs" { // Node built-in module fs }
或者深層模塊聲明:
declare module "sample/lib1" { export let name: number; } declare module "sample/lib2" { export let value: number; } declare module "sample" { export * from "sample/lib1"; export * from "sample/lib2"; }
這是模塊導出聲明寫法作不到的。
綜上所述,最直觀的解釋是: