自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何在 TypeScript 中使用命名空間

開發(fā) 前端
TypeScript 是 JavaScript 語言的擴展,它使用 JavaScript 運行時和編譯時類型檢查器。

介紹

TypeScript 是 JavaScript 語言的擴展,它使用 JavaScript 運行時和編譯時類型檢查器。

TypeScript 提供了多種方法來表示代碼中的對象,其中一種是使用接口。 TypeScript 中的接口有兩種使用場景:您可以創(chuàng)建類必須遵循的約定,例如,這些類必須實現(xiàn)的成員,還可以在應用程序中表示類型,就像普通的類型聲明一樣。 

您可能會注意到接口和類型共享一組相似的功能。

事實上,一個幾乎總是可以替代另一個。

主要區(qū)別在于接口可能對同一個接口有多個聲明,TypeScript 將合并這些聲明,而類型只能聲明一次。您還可以使用類型來創(chuàng)建原始類型(例如字符串和布爾值)的別名,這是接口無法做到的。

TypeScript 中的接口是表示類型結構的強大方法。它們允許您以類型安全的方式使用這些結構并同時記錄它們,從而直接改善開發(fā)人員體驗。

在今天的文章中,我們將在 TypeScript 中創(chuàng)建接口,學習如何使用它們,并了解普通類型和接口之間的區(qū)別。

我們將嘗試不同的代碼示例,可以在 TypeScript 環(huán)境或 TypeScript Playground(一個允許您直接在瀏覽器中編寫 TypeScript 的在線環(huán)境)中遵循這些示例。

準備工作

要完成今天的示例,我們將需要做如下準備工作:

  • 一個環(huán)境。我們可以執(zhí)行 TypeScript 程序以跟隨示例。要在本地計算機上進行設置,我們將需要準備以下內容。
  1. 為了運行處理 TypeScript 相關包的開發(fā)環(huán)境,同時安裝了 Node 和 npm(或 yarn)。本文教程中使用 Node.js 版本 為14.3.0 和 npm 版本 6.14.5 進行了測試。要在 macOS 或 Ubuntu 18.04 上安裝,請按照如何在 macOS 上安裝 Node.js 和創(chuàng)建本地開發(fā)環(huán)境或如何在 Ubuntu 18.04 上安裝 Node.js 的使用 PPA 安裝部分中的步驟進行操作。如果您使用的是適用于 Linux 的 Windows 子系統(tǒng) (WSL),這也適用。
  2. 此外,我們需要在機器上安裝 TypeScript 編譯器 (tsc)。為此,請參閱官方 TypeScript 網站。
  • 如果你不想在本地機器上創(chuàng)建 TypeScript 環(huán)境,你可以使用官方的 TypeScript Playground 來跟隨。
  • 您將需要足夠的 JavaScript 知識,尤其是 ES6+ 語法,例如解構、rest 運算符和導入/導出。如果您需要有關這些主題的更多信息,建議閱讀我們的如何用 JavaScript 編寫代碼系列。
  • 本文教程將參考支持 TypeScript 并顯示內聯(lián)錯誤的文本編輯器的各個方面。這不是使用 TypeScript 所必需的,但確實可以更多地利用 TypeScript 功能。為了獲得這些好處,您可以使用像 Visual Studio Code 這樣的文本編輯器,它完全支持開箱即用的 TypeScript。你也可以在 TypeScript Playground 中嘗試這些好處。

本教程中顯示的所有示例都是使用 TypeScript 4.2.2 版創(chuàng)建的。

在 TypeScript 中創(chuàng)建命名空間

在本節(jié)中,我們將一起來學習在 TypeScript 中創(chuàng)建命名空間以說明一般語法。

要創(chuàng)建命名空間,我們將使用命名空間關鍵字,后跟命名空間的名稱,然后是 {} 塊。 

例如,我們將創(chuàng)建一個 DatabaseEntity 命名空間來保存數(shù)據庫實體,就像我們使用對象關系映射 (ORM) 庫一樣。 

將以下代碼添加到新的 TypeScript 文件中:

namespace DatabaseEntity {
}

這聲明了 DatabaseEntity 命名空間,但尚未向該命名空間添加代碼。 接下來,在命名空間中添加一個 User 類來表示數(shù)據庫中的一個 User 實體:

namespace DatabaseEntity {
class User {
constructor(public name: string) {}
}
}

我們可以在命名空間中正常使用 User 類。 為了說明這一點,創(chuàng)建一個新的 User 實例并將其存儲在 newUser 變量中:

namespace DatabaseEntity {
class User {
constructor(public name: string) {}
}

const newUser = new User("Jon");
}

這是有效的代碼。 

但是,如果我們嘗試在命名空間之外使用 User,TypeScript 編譯器會給我們返回錯誤 2339:

Out
putProperty 'User' does not exist on type 'typeof DatabaseEntity'. (2339)

如果我們想在命名空間之外使用類,則必須首先導出 User 類以在外部可用,如下面突出顯示的代碼所示:

namespace DatabaseEntity {
exportclass User {
constructor(public name: string) {}
}

const newUser = new User("Jon");
}

我們現(xiàn)在可以使用完全限定名稱訪問 DatabaseEntity 命名空間之外的 User 類。 在這種情況下,完全限定名稱是 DatabaseEntity.User:


namespace DatabaseEntity {
export class User {
constructor(public name: string) {}
}

const newUser = new User("Jon");
}

const newUserOutsideNamespace = new DatabaseEntity.User("Jane");

我們可以從命名空間中導出任何內容,包括變量,然后這些變量將成為命名空間中的屬性。 

在以下代碼中,我們將導出 newUser 變量:

namespace DatabaseEntity {
export class User {
constructor(public name: string) {}
}

exportconst newUser = new User("Jon");
}

console.log(DatabaseEntity.newUser.name);

由于變量 newUser 已導出,因此,我們可以將其作為命名空間的屬性進行訪問。 運行此代碼會將以下內容打印到控制臺:

Output
Jon

就像接口一樣,TypeScript 中的命名空間也允許聲明合并。 這意味著同一命名空間的多個聲明將合并為一個聲明。 如果我們需要稍后在代碼中擴展命名空間,這可以增加命名空間的靈活性。

使用前面的示例,這意味著如果我們再次聲明 DatabaseEntity 命名空間,我們將能夠使用更多屬性擴展命名空間。 使用另一個命名空間聲明將一個新類 UserRole 添加到我們的 DatabaseEntity 命名空間:

namespace DatabaseEntity {
export class User {
constructor(public name: string) {}
}

export const newUser = new User("Jon");
}

namespace DatabaseEntity {
export class UserRole {
constructor(public user: User, public role: string) {}
}

export const newUserRole = new UserRole(newUser, "admin");
}

在新的 DatabaseEntity 命名空間聲明中,我們可以使用以前在 DatabaseEntity 命名空間中導出的任何成員,包括從以前的聲明中導出的成員,而不必使用它們的完全限定名。

我們正在使用在第一個命名空間中聲明的名稱來將 UserRole 構造函數(shù)中的用戶參數(shù)的類型設置為 User 類型,并在使用 newUser 值創(chuàng)建新的 UserRole 實例時。這僅是可能的,因為,我們在之前的命名空間聲明中導出了這些內容。

現(xiàn)在,我們已經了解了命名空間的基本語法,我們可以繼續(xù)研究 TypeScript 編譯器如何將命名空間轉換為 JavaScript。

檢查使用命名空間時生成的 JavaScript 代碼

TypeScript 中的命名空間不僅僅是一個編譯時特性。他們還更改了生成的 JavaScript 代碼。要了解有關命名空間如何工作的更多信息,我們可以分析支持此 TypeScript 功能的 JavaScript。

在這一步中,我們將獲取上一節(jié)中的代碼片段并檢查它們的底層 JavaScript 實現(xiàn)。

以我們在第一個示例中使用的代碼為例:

namespace DatabaseEntity {
export class User {
constructor(public name: string) {}
}

export const newUser = new User("Jon");
}

console.log(DatabaseEntity.newUser.name);

TypeScript 編譯器會為此 TypeScript 片段生成以下 JavaScript 代碼:

"use strict";
var DatabaseEntity;
(function (DatabaseEntity) {
class User {
constructor(name) {
this.name = name;
}
}
DatabaseEntity.User = User;
DatabaseEntity.newUser = new User("Jon");
})(DatabaseEntity || (DatabaseEntity = {}));
console.log(DatabaseEntity.newUser.name);

為了聲明 DatabaseEntity 命名空間,TypeScript 編譯器創(chuàng)建一個名為 DatabaseEntity 的未初始化變量,然后,創(chuàng)建一個立即調用函數(shù)表達式 (IIFE)。 此 IIFE 接收單個參數(shù) DatabaseEntity || (DatabaseEntity = {}),這是 DatabaseEntity 變量的當前值。 如果未設置為真值,則將變量的值設置為空對象。

在將 DatabaseEntity 的值傳遞給 IIFE 時將其設置為空值是可行的,因為賦值操作的返回值是被賦值的值。 在這種情況下,這是空對象。

在 IIFE 內部,創(chuàng)建了 User 類,然后,將其分配給 DatabaseEntity 對象的 User 屬性。 newUser 屬性也是如此,我們將屬性分配給新 User 實例的值。

現(xiàn)在看一下第二個代碼示例,其中有多個命名空間聲明:


namespace DatabaseEntity {
export class User {
constructor(public name: string) {}
}

export const newUser = new User("Jon");
}

namespace DatabaseEntity {
export class UserRole {
constructor(public user: User, public role: string) {}
}

export const newUserRole = new UserRole(newUser, "admin");
}

生成的 JavaScript 代碼如下所示:?

"use strict";
var DatabaseEntity;
(function (DatabaseEntity) {
class User {
constructor(name) {
this.name = name;
}
}
DatabaseEntity.User = User;
DatabaseEntity.newUser = new User("Jon");
})(DatabaseEntity || (DatabaseEntity = {}));
(function (DatabaseEntity) {
class UserRole {
constructor(user, role) {
this.user = user;
this.role = role;
}
}
DatabaseEntity.UserRole = UserRole;
DatabaseEntity.newUserRole = new UserRole(DatabaseEntity.newUser, "admin");
})(DatabaseEntity || (DatabaseEntity = {}));

代碼的開頭看起來與之前的相同,未初始化的變量 DatabaseEntity,然后是一個 IIFE,其中實際代碼設置了 DatabaseEntity 對象的屬性。這一次,雖然,還有另一個 IIFE。這個新的 IIFE 與 DatabaseEntity 命名空間的第二個聲明相匹配。

現(xiàn)在,當執(zhí)行第二個 IIFE 時,DatabaseEntity 已經綁定到一個對象,因此,我們只是通過添加額外屬性來擴展已經可用的對象。

我們現(xiàn)在已經了解了 TypeScript 命名空間的語法以及它們在底層 JavaScript 中的工作方式。有了這個上下文,我們現(xiàn)在可以運行命名空間的一個常見用例:為外部庫定義類型而無需鍵入。

使用命名空間為外部庫提供類型

在這部分內容中,我們將體驗命名空間有用的場景之一:為外部庫創(chuàng)建模塊聲明。為此,我們將在 TypeScript 項目中編寫一個新文件來聲明類型,然后更改 tsconfig.json 文件以使 TypeScript 編譯器識別類型。

注意:要執(zhí)行后續(xù)步驟,需要一個可以訪問文件系統(tǒng)的 TypeScript 環(huán)境。如果您使用的是 TypeScript Playground,則可以通過單擊頂部菜單中的導出,然后在 CodeSandbox 中打開,將現(xiàn)有代碼導出到 CodeSandbox 項目。這將允許您創(chuàng)建新文件并編輯 tsconfig.json 文件。

并非 npm 注冊表中的每個可用包都捆綁了自己的 TypeScript 模塊聲明。這意味著在項目中安裝包時,您可能會遇到與包缺少類型聲明相關的編譯錯誤,或者必須使用所有類型都設置為 any 的庫。根據您使用 TypeScript 的嚴格程度,這可能是一個不希望的結果。

希望這個包將有一個由 DefinetelyTyped 社區(qū)創(chuàng)建的 @types 包,允許您安裝包并獲得該庫的工作類型。

但是,情況并非總是如此,有時您必須處理一個不捆綁其自己的類型模塊聲明的庫。在這種情況下,如果您想保持您的代碼完全類型安全,您必須自己創(chuàng)建模塊聲明。

例如,假設您正在使用一個名為 example-vector3 的向量庫,它使用單個方法 add 導出單個類 Vector3。此方法用于將兩個 Vector3 向量相加。

庫中的代碼可能如下所示:


export class Vector3 {
super(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}

add(vec) {
let x = this.x + vector.x;
let y = this.y + vector.y;
let z = this.z + vector.z;

let newVector = new Vector3(x, y, z);

return newVector
}
}

這導出了一個類,該類創(chuàng)建具有 x、y 和 z 屬性的向量,用于表示向量的坐標分量。

接下來,看一下使用假設庫的示例代碼:

index.ts

import { Vector3 } from "example-vector3";

const v1 = new Vector3(1, 2, 3);
const v2 = new Vector3(1, 2, 3);

const v3 = v1.add(v2);

example-vector3 庫沒有與它自己的類型聲明捆綁在一起,因此, TypeScript 編譯器將給出錯誤 2307:

Output
Cannot find module 'example-vector3' or its corresponding type declarations. ts(2307)

為了解決這個問題,我們現(xiàn)在將為這個包創(chuàng)建一個類型聲明文件。 

首先,創(chuàng)建一個名為 types/example-vector3/index.d.ts 的新文件。

然后,在您喜歡的編輯器中打開它。 

在此文件中寫入以下代碼:

declare module "example-vector3" {
export = vector3;

namespace vector3 {
}
}

在此代碼中,我們正在為 example-vector3 模塊創(chuàng)建類型聲明。 代碼的第一部分是聲明模塊塊本身。 TypeScript 編譯器將解析這個塊并解釋其中的所有內容,就好像它是模塊本身的類型表示一樣。 這意味著我們在此處聲明的任何內容,TypeScript 都將用于推斷模塊的類型。 

現(xiàn)在,您說這個模塊導出了一個名為 vector3 的命名空間,該命名空間目前是空的。

保存并退出此文件。

TypeScript 編譯器當前不知道您的聲明文件,因此您必須將其包含在您的 tsconfig.json 中。 

為此,通過將 types 屬性添加到 compilerOptions 選項來編輯項目 tsconfig.json:

{
"compilerOptions": {
...
"types": ["./types/example-vector3/index.d.ts"]
}
}

現(xiàn)在,如果我們返回原始代碼,我們將看到錯誤已更改。TypeScript 編譯器現(xiàn)在給出錯誤是2305:

Output
Module '"example-vector3"' has no exported member 'Vector3'. ts(2305)

當我們?yōu)?example-vector3 創(chuàng)建模塊聲明時,導出當前設置為空命名空間。 沒有從該命名空間中導出 Vector3 類。

重新打開 types/example-vector3/index.d.ts 并編寫以下代碼:


declare module "example-vector3" {
export = vector3;

namespace vector3 {
export class Vector3 {
constructor(x: number, y: number, z: number);
add(vec: Vector3): Vector3;
}
}
}

在此代碼中,請注意,我們現(xiàn)在如何在 vector3 命名空間內導出一個類。模塊聲明的主要目標是提供由庫公開的值的類型信息。這樣,我們可以以類型安全的方式使用它。

在這種情況下,我們知道 example-vector3 庫提供了一個名為 Vector3 的類,該類在構造函數(shù)中接受三個數(shù)字,并且具有用于將兩個 Vector3 實例相加的 add 方法,并返回一個新實例作為結果。

我們無需在此處提供實現(xiàn),只需提供類型信息本身。不提供實現(xiàn)的聲明在 TypeScript 中稱為環(huán)境聲明,通常在 .d.ts 文件中創(chuàng)建這些聲明。

此代碼現(xiàn)在將正確編譯并具有 Vector3 類的正確類型。

使用命名空間,我們可以將庫導出的內容隔離到單個類型單元中,在本例中為 vector3 命名空間。這使得自定義模塊聲明變得更加容易,甚至可以通過將類型聲明提交到 DefinetelyTyped 存儲庫來使所有開發(fā)人員都可以使用它。

最后結論

在今天的教程中,我們了解了 TypeScript 中命名空間的基本語法,并檢查了 TypeScript 編譯器將其更改為的 JavaScript。

我們還嘗試了命名空間的一個常見用例:為尚未鍵入的外部庫提供環(huán)境類型。

雖然,不推薦使用命名空間,但并不總是建議在代碼庫中使用命名空間作為代碼組織機制?,F(xiàn)代代碼應該使用 ES 模塊語法,因為它具有命名空間提供的所有功能,并且從 ECMAScript 2015 開始,它成為規(guī)范的一部分。

但是,在創(chuàng)建模塊聲明時,仍然建議使用命名空間,因為它允許更簡潔的類型聲明。

如果你還想閱讀更多有關 TypeScript 的教程文章,請看下面的推薦閱讀內容,如果你覺得我今天的教程不錯,請點贊我,關注我,并將這篇文章分享給你的朋友,也許能夠幫助到他。

最后,感謝你的閱讀,編程快樂!

責任編輯:華軒 來源: web前端開發(fā)
相關推薦

2022-05-17 08:25:10

TypeScript接口前端

2023-01-05 17:13:28

TypeScript泛型組件

2022-05-10 09:12:16

TypeScript裝飾器

2023-10-18 16:30:50

2020-07-13 07:00:21

Kubernetes

2018-04-28 09:12:42

Linux

2011-05-20 14:54:46

ADO.NET命名空間

2011-05-20 14:54:46

ADO.NET

2011-08-10 09:31:41

Hibernateunion

2021-03-09 07:27:40

Kafka開源分布式

2015-08-27 09:46:09

swiftAFNetworkin

2021-06-09 09:36:18

DjangoElasticSearLinux

2022-06-23 08:00:53

PythonDateTime模塊

2024-01-18 08:37:33

socketasyncio線程

2025-03-21 09:58:59

Python數(shù)據類型安全

2021-09-10 10:30:22

Java代碼

2023-12-01 09:18:27

AxiosAxios 庫

2015-11-26 10:57:56

DockerOpen vSwitc

2022-10-25 09:07:28

Linuxxargs命令

2019-09-16 19:00:48

Linux變量
點贊
收藏

51CTO技術棧公眾號