【譯】TypeScript 類型聲明文件(.d.ts)編寫之深入(Definition File Theory: A Deep Dive)

通過(guò)結(jié)構(gòu)化模塊,為所需的 API 提供精確的原型并不是一件容易的事情。例如:我們可能需要一個(gè)模塊在被調(diào)用時(shí),帶上 new 關(guān)鍵字與不帶 new 關(guān)鍵字來(lái)生成不同的類型,在層級(jí)關(guān)系中,暴露出不同的命名,并且還在模塊對(duì)象上具有一些屬性。

通過(guò)閱讀本指南,您將擁有編寫復(fù)雜定義文件的工具,這些文件將提供友好的 API 表面。 本指南關(guān)注模塊(或 UMD)庫(kù),因?yàn)檫@里的選項(xiàng)更多。

一、關(guān)鍵概念(Key Concepts)

通過(guò)理解 TypeScript 的一些關(guān)鍵概念,您可以充分理解如何進(jìn)行任何形式的定義。

1、類型(Types)

如果您正在閱讀本指南,您可能已經(jīng)大致了解 TypeScript 中的類型。 然而,再明確一下,一種類型可以通過(guò)以下形式被引入:

  • 類型別名聲明:type sn = number | string;
  • 接口聲明:interface I { x: number[]; }
  • 類聲明:class C { }
  • 枚舉聲明:enum E { A, B, C }
  • import 聲明指向一個(gè)類型

2、值(Values)

與類型一樣,您可能已經(jīng)理解了什么是 Value。 Value 是我們可以在表達(dá)式中引用的運(yùn)行時(shí)名稱。 例如:let x = 5; 創(chuàng)建一個(gè)名為 x 的 Value。
  明確一下通過(guò)以下形式創(chuàng)建 Value:

  • let、constvar 聲明
  • namespacemodule 聲明包含一個(gè) Value
  • enum 聲明
  • class 聲明
  • import 聲明指向一個(gè)值
  • function 聲明

3、命名空間(Namespaces)

類型可以存在于命名空間中。例如:有 let x: A.B.C 聲明,我們說(shuō)類型 C 來(lái)自命名空間 A.B。
  這種區(qū)別是微妙重要的——在這里,A.B 不一定是必要的類型或值。

二、簡(jiǎn)單的組合:一個(gè)名字,多重含義

給定一個(gè)名稱 A,我們可以為 A 找到三種不同的含義:一個(gè)類型,一個(gè)值或一個(gè)命名空間。 名稱的解釋方式取決于其使用的上下文。 例如,在聲明 let m:A.A = A; 中,A 首先用作命名空間,然后用作類型名稱,然后用作值。 這些含義最終可能指的是完全不同的聲明!
  這看起來(lái)可能會(huì)讓人困惑,但只要我們不過(guò)分使用,它實(shí)際上非常方便。 我們來(lái)看看這種組合行為的一些有用的方面。

1、內(nèi)建組合(Built-in Combinations)

精明的讀者會(huì)注意到,例如:class 同時(shí)出現(xiàn)在 typevalue 清單中。 聲明 class C {} 創(chuàng)建了兩項(xiàng)內(nèi)容:

  1. 類型 C——類 C 的實(shí)例原型
  2. C——類 C 的構(gòu)造函數(shù)

枚舉聲明的行為類似。

2、用戶組合(User Combinations)

假設(shè)我們寫了一個(gè)模塊文件 foo.d.ts

export var SomeVar: { a: SomeType };
export interface SomeType {
  count: number;
}

然后使用它:

import * as foo from './foo';
let x: foo.SomeType = foo.SomeVar.a;
console.log(x.count);

這工作得很好,但我們可以想象 SomeTypeSomeVar 密切相關(guān),所以你希望它們有相同的名字。 我們可以使用組合來(lái)以相同的名稱顯示這兩個(gè)不同的對(duì)象(值和類型)Bar

export var Bar: { a: Bar };
export interface Bar {
  count: number;
}

這為消費(fèi)代碼中的解構(gòu)提供了一個(gè)非常好的機(jī)會(huì):

import { Bar } from './foo';
let x: Bar = Bar.a;
console.log(x.count);

同樣,我們?cè)谶@里使用 Bar 同時(shí)作為類型和值。 請(qǐng)注意,我們不必將 Bar的值聲明為 Bar 類型——它們是獨(dú)立的。

三、高級(jí)組合(Advanced Combinations)

某些類型的聲明可以在多個(gè)聲明中組合使用。 例如,class C { }interface C { } 可以共存,并且都為 C 類型提供屬性。

只要不產(chǎn)生沖突,這是合法的。 一般的經(jīng)驗(yàn)法則是:

  • 總是與其他相同名稱的值沖突,除非它們被聲明為命名空間
  • 如果使用類型別名進(jìn)行聲明類型,如:type s = string,則可能會(huì)產(chǎn)生沖突;
  • 命名空間永不沖突。

我們來(lái)看看如何使用它。

1、使用 interface 添加(Adding using an interface

我們可以使用另一個(gè) interface 聲明將其他成員添加到現(xiàn)有 interface 聲明中:

interface Foo {
  x: number;
}
// ... elsewhere ...
interface Foo {
  y: number;
}
let a: Foo = ...;
console.log(a.x + a.y); // OK

這也適用于類:

class Foo {
  x: number;
}
// ... elsewhere ...
interface Foo {
  y: number;
}
let a: Foo = ...;
console.log(a.x + a.y); // OK

請(qǐng)注意,我們不能使用 interface 添加類型別名,如:type s = string;。

2、使用 namespace 添加(Adding using a namespace

namespace 聲明可用于以任何不會(huì)產(chǎn)生沖突的方式,添加新的類型、值和命名空間。
例如,為類添加靜態(tài)成員:

class C {
}
// ... elsewhere ...
namespace C {
  export let x: number;
}
let y = C.x; // OK

請(qǐng)注意,在這個(gè)例子中,我們向 C 的靜態(tài)端(它的構(gòu)造函數(shù))添加了一個(gè)值。 這是因?yàn)槲覀兲砑恿艘粋€(gè)值,并且所有值的容器都是另一個(gè)值(類型由命名空間包含,命名空間由其他命名空間包含)。

我們也可以為類添加一個(gè)命名空間類型:

class C {
}
// ... elsewhere ...
namespace C {
  export interface D { }
}
let y: C.D; // OK

在這個(gè)例子中,直到我們寫了命名空間聲明之前,沒(méi)有一個(gè)命名空間 C。C 作為命名空間的含義,與該類創(chuàng)建的 C類型的含義不沖突。

最后,我們可以使用命名空間聲明來(lái)執(zhí)行許多不同的合并。 這不是一個(gè)特別實(shí)際的例子,但顯示了各種有趣的行為:

namespace X {
  export interface Y { }
  export class Z { }
}

// ... elsewhere ...
namespace X {
  export var Y: number;
  export namespace Z {
    export class C { }
  }
}
type X = string;

在本例中,第一個(gè)塊創(chuàng)建以下名稱含義:

  • X(因?yàn)?namespace 聲明包含了值 Z
  • 命名空間 X(因?yàn)?namespace 聲明包含了類型 Y
  • 類型 Y 在命名空間 X
  • 類型 Z 在命名空間 X 中(類的實(shí)例原型)
  • Z,屬于 X 值的屬性(類的構(gòu)造器)

第二個(gè)塊創(chuàng)建以下名稱含義:

  • Ynumber 類型,X 值的屬性)
  • 命名空間 Z
  • ZX 值的屬性)
  • 類型 C(在命名空間 X.Z 中)
  • CX.Z 值的屬性)
  • 類型 X

四、使用 export =import

一個(gè)重要的規(guī)則,是 exportimport 聲明輸出或輸入它們目標(biāo)的所有含義。

五、參考資料

譯自 Definition File Theory: A Deep Dive

(完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容