迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 >

TypeScript 如何使用命名空间(超详细)

作者:迹忆客 最近更新:2023/01/08 浏览次数:

TypeScript 是 JavaScript 语言的扩展,它使用 JavaScript 的运行时和编译时类型检查器。 在 TypeScript 中,我们可以使用命名空间来组织代码。 TypeScript 中的命名空间以前称为内部模块,它基于 ECMAScript 模块的早期草案。 在 ECMAScript 规范草案中,内部模块在 2013 年 9 月左右被删除,但 TypeScript 以不同的名称保留了这个想法。

命名空间允许开发人员创建可用于保存多个值的单独组织单元,例如属性、类、类型和接口。 在本篇文章中,我们将创建和使用命名空间来说明语法以及它们的用途。 它将引导我们了解声明和合并命名空间的代码示例,命名空间如何在后台作为 JavaScript 代码工作,以及如何使用它们为外部库声明类型而无需再手动引用。

在 TypeScript 教程中我们简单介绍过命名空间。在这里我们详细介绍其用法。

在 TypeScript 中创建命名空间

在本节中,我们将在 TypeScript 中创建命名空间来说明一般语法。

要创建命名空间,将使用命名空间关键字,后跟命名空间的名称,然后是 {} 块。 例如,我们将创建一个 DatabaseEntity 命名空间来保存数据库实体,就像我们使用对象关系映射 (ORM) 库一样。 将以下代码添加到新的 TypeScript 文件中:

namespace DatabaseEntity {
}

这声明了 DatabaseEntity 命名空间,但尚未向该命名空间添加代码。 接下来,在命名空间中添加一个 User 类来表示数据库中的 User 实体:

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

可以在命名空间中正常使用 User 类。 为了说明这一点,创建一个新的 User 实例并将其存储在 newUser 变量中:

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

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

这是有效的代码。 但是,如果尝试在命名空间之外使用 User,TypeScript 编译器会给您错误 2339:

TypeScript 命名空间错误内容

如果您想在命名空间之外使用类,则必须首先导出 User 类使其可以在外部可用,如下面代码所示:

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

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

现在可以使用完全限定名称访问 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) {}
  }

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

console.log(DatabaseEntity.newUser.name);

运行示例

由于变量 newUser 已导出,因此我们可以将其作为命名空间的属性进行访问。 运行此代码会打印如下内容:

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");
}
console.log("姓名:"+DatabaseEntity.newUserRole.user.name);
console.log("角色:"+DatabaseEntity.newUserRole.role);

运行示例

在新的 DatabaseEntity 命名空间声明中,我们可以使用以前在 DatabaseEntity 命名空间中导出的任何成员,包括从以前的声明中导出的成员,而不必使用它们的完全限定名称。 在使用 newUser 值创建新的 UserRole 实例时,我们使用在第一个命名空间中声明的名称来将 UserRole 构造函数中的用户参数的类型设置为 User 类型。 这仅是可能的,因为在之前的命名空间声明中导出了这些内容。

上面示例运行结果如下

姓名:Jon
角色:admin

现在我们已经了解了命名空间的基本语法,接下来可以继续研究 TypeScript 编译器如何将命名空间转换为 JavaScript。


检查使用命名空间时生成的 JavaScript 代码

TypeScript 中的命名空间不仅仅是一个编译时特性。 他们还更改了生成的 JavaScript 代码。 要了解有关命名空间如何工作的更多信息,我们可以分析支持此 TypeScript 功能的 JavaScript。 在这一步中,将获取上一节中的代码片段并查看它们的底层 JavaScript 实现。

以我们在第一个示例中使用的代码为例:

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 编译器创建一个名为 DatabaseEntity 的未初始化变量,然后创建一个立即调用函数表达式 (IIFE)。 此 IIFE 接收单个参数 DatabaseEntity || (DatabaseEntity = {}),这是 DatabaseEntity 变量的当前值。 如果未设置为真值,则将变量的值设置为空对象。

在将 DatabaseEntity 的值传递给 IIFE 时将其设置为空值是可行的,因为赋值操作的返回值是被赋值的值。 在这种情况下,这是空对象。

在 IIFE 中,创建了 User 类,然后将其分配给 DatabaseEntity 对象的 User 属性。 newUser 属性也是如此,我们将属性分配给新 User 实例的值。

现在看一下第二个代码示例,其中有多个命名空间声明:

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 命名空间的第二个声明相匹配。

现在,当执行第二个 IIFE 时,DatabaseEntity 已经绑定到一个对象,因此我们只是通过添加额外属性来扩展已经可用的对象。

现在已经了解了 TypeScript 命名空间的语法以及它们在底层 JavaScript 中的工作方式。 有了这个上下文,现在可以运行命名空间的一个常见用例:为外部库定义类型限定。

相关文章

在 TypeScript 中声明一个 ES6 Map

发布时间:2023/03/05 浏览次数:181 分类:WEB前端

本篇文章将指导我们使用编码示例在 TypeScript 中定义 ES6 Map。 这解释了什么是 ES6 Map及其用途。 让我们首先看看 ES6 是什么以及为什么使用它们。 ES6 Map 在 ES6 之前,我们使用对象通过将

如何在 TypeScript 中合并对象

发布时间:2023/02/20 浏览次数:217 分类:编程语言

使用扩展语法 ... 合并 TypeScript 中的对象,例如 const obj3 = { ...obj1, ...obj2} 。 最终对象的类型将被成功推断,因此尝试添加或删除属性会导致类型检查器显示错误。 const obj1 = { name : 迹忆

如何在 TypeScript 中对数组进行排序

发布时间:2023/02/15 浏览次数:196 分类:编程语言

在 TypeScript 中对 Numbers 数组进行排序 使用 sort() 方法对 TypeScript 中的数组进行排序,例如 numArray.sort((a, b) = a - b) 。 sort 方法采用定义排序顺序的函数作为参数。 在对数值数组进行排序

如何在 TypeScript 中扩展类型

发布时间:2023/02/15 浏览次数:230 分类:编程语言

在 TypeScript 中扩展类型 使用交集类型来扩展 TypeScript 中的类型,例如 type TypeB = TypeA {age: number;} 。交集类型使用 符号定义,用于组合现有对象类型。 我们可以根据需要多次使用 运算符

TypeScript 中如何创建 Date 日期对象

发布时间:2023/02/14 浏览次数:219 分类:编程语言

使用 Date 类型在 TypeScript 中键入 Date 对象,例如 const date: Date = new Date() 。 Date() 构造函数返回一个类型为 Date 的对象。 该接口定义了 Date 对象上所有内置方法的类型。 // ?️ const da

在 TS 中使用 {[key:string]: string} 和 {[key:string]: any}

发布时间:2023/02/14 浏览次数:125 分类:编程语言

TypeScript 中的 {[key: string]: string} 类型 {[key: string]: string} 语法是 TypeScript 中的索引签名,当我们事先不知道类型属性的所有名称但知道值的形状时使用。 索引签名指定字符串类型的键和

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便