【稳妥的TypeScript】命名空间

大家好,我是一碗周,一个不想被喝(内卷)的前端。如果写的文章有幸可以得到你的青睐,万分有幸~

写在前面

命名空间namespace在TypeScript1.5版本之前是叫做内部模块 ,那是因为ES6中的模块还没有称为正式标准,在ES6提出该规范时,TypeScript1.5 正事更名为命名空间 ,用namespace来定义。

定义和使用

定义

命名空间的定义就相当于定义了一个对象,该对象中可以定义变量、接口、类、方法等等,但是如果不使用export关键字指定此内容为外部可见的话,外部是没有办法访问到的。

接下来定义一个正则验证的一个.ts文件,实现代码如下:

// validation.ts
// 通过 namespace 创建一个名为 Validation 的命名空间
namespace Validation {
    // 定义一个正则表达式
    const isLetterReg = /^[A-Za-z]+$/
    // 这里在定义一个正则表达式,与上一个的区别就是这个正则表达式通过export导出了
    export const isNumberReg = /^[0-9]+$/
    // 导出一个方法
    export const checkLetter = (text: any) => {
        return isLetterReg.test(text)
    }
}

在上面的代码中,我们定义了一个名为Validation的命名空间,并在里面定义了两个属性和一个方法,并将一个属性和一个方法导出(命名空间的中导出使用export关键字)。

使用

在某个文件使用命名空间中的内容只需要在使用外部命名空间的地方使用/// <reference path=“namespace.ts”/>来引入,注意三斜线///开头,然后在 path 属性指定相对于当前文件,这个命名空间文件的路径。具体代码如下:

// index.ts
/// <reference  path='validation.ts' />
let isLetter = Validation.checkLetter('text')
const reg = Validation.isNumberReg
console.log(isLetter)
console.log(reg)

值得注意的是第一行的/// <reference path='validation.ts' />。语法结构是不能错的,否则编译是不通过的。

编译命令如下:

tsc --outFile src/index.js index.ts

outFile参数是用于将输出文件合并为一个文件

编译后的index.js文件如下:

// 通过 namespace 创建一个名为 Validation 的命名空间
var Validation;
(function (Validation) {
    // 定义一个正则表达式
    var isLetterReg = /^[A-Za-z]+$/;
    // 这里在定义一个正则表达式,与上一个的区别就是这个正则表达式通过export导出了
    Validation.isNumberReg = /^[0-9]+$/;
    // 导出一个方法
    Validation.checkLetter = function (text) {
        return isLetterReg.test(text);
    };
})(Validation || (Validation = {}));
/// <reference  path='validation.ts' />
var isLetter = Validation.checkLetter('text');
var reg = Validation.isNumberReg;
console.log(isLetter);
console.log(reg);

拆分为多个文件

随着我们的开发内容的不断增加,我们可以将同一个命名命名空间拆分为多个文件分开维护,尽管我们将其拆分为为多个文件,但是他们仍然属于一个命名空间,示例代码如下:

LetterValidation.ts

// LetterValidation.ts
namespace Validation {
    export const isLetterReg = /^[A-Za-z]+$/
    export const checkLetter = (text: any) => {
        return isLetterReg.test(text)
    }
}

NumberValidation.ts

// NumberValidation.ts
namespace Validation {
    export const isNumberReg = /^[0-9]+$/
    export const checkNumber = (text: any) => {
        return isNumberReg.test(text)
    }
}

index.ts

// index.ts
/// <reference path="./LetterValidation.ts"/>
/// <reference path="./NumberValidation.ts"/>
let isLetter = Validation.checkLetter('text')
const reg = Validation.isNumberReg
console.log(isLetter)

我们使用命令行来编译一下:

tsc --outFile src/index.js index.ts

最终编译后的index.js代码如下:

// LetterValidation.ts
var Validation;
(function (Validation) {
    Validation.isLetterReg = /^[A-Za-z]+$/;
    Validation.checkLetter = function (text) {
        return Validation.isLetterReg.test(text);
    };
})(Validation || (Validation = {}));
// NumberValidation.ts
var Validation;
(function (Validation) {
    Validation.isNumberReg = /^[0-9]+$/;
    Validation.checkNumber = function (text) {
        return Validation.isNumberReg.test(text);
    };
})(Validation || (Validation = {}));
/// <reference path="./LetterValidation.ts"/>
/// <reference path="./NumberValidation.ts"/>
var isLetter = Validation.checkLetter('text');
var reg = Validation.isNumberReg;
console.log(isLetter);

由编译结果可以看出,我们先引入了LetterValidation.ts文件,后引入NumberValidation.ts文件,他们最终编译后的结果也是按照引入顺序编译的。

别名

别名是一种简化命名空间的操作方式,其语法是使用import关键字,使用方式如下:

import q = x.y.z

值得注意的是该方式不要与家长模块的import x = require('name')语法混淆,这里的语法是为指定的符号创建一个别名。可以使用该方法为任意标识符创建别名,也包括引入模块中的对象。

// 定义一个命名空间
namespace Shapes {
    // 在命名空间中定义一个子命名空间,并将其导出
    export namespace Polygons {
        export class Triangle {}
        export class Square {}
    }
}
// 通过 import 的语法将导出的子命名空间重新命名为 polygons
import polygons = Shapes.Polygons
// 通过导出的命名空间实例化 Square 类
let sq = new polygons.Square()

通过这个例子我们可以看到,使用import关键字来定义命名空间中某个输出元素的别名,可以减少我们深层次获取属性的成本。

往期推荐

### TypeScript 命名空间的适用情况 当处理较小规模的应用程序或特定功能模块时,如果希望避免全局命名污染并保持代码整洁有序,则可以考虑使用命名空间。然而,在现代Web开发实践中更倾向于采用ES6模块化方案[^3]。 对于遗留系统的迁移工作而言,利用命名空间能够逐步过渡到更加现代化的架构设计模式下而不至于一次性重构整个项目结构;另外,在某些特殊场合比如编写第三方库的时候也可以借助命名空间来封装内部实现细节从而保护私有成员不受外界干扰[^1]。 ### 使用场景示例 #### 场景一:防止变量冲突 假设在一个页面中有多个独立的功能区域都需要定义名为`User`的对象类型: ```typescript // 定义第一个命名空间中的 User 类型 namespace AdminPanel { export interface User { id: number; username: string; role: "admin"; } } // 定义第二个命名空间中的 User 类型 namespace PublicSite { export class User { constructor(public name: string, public email?: string) {} } } ``` 通过这种方式可以在不引起任何名称冲突的情况下分别创建两个具有相同名字但含义不同的实体[^4]。 #### 场景二:模拟类继承关系 有时为了简化依赖注入过程或者模仿面向对象编程里的继承机制,可以通过嵌套的方式构建层次化的命名空间体系: ```typescript namespace Shapes { export namespace Circle { export function draw(radius: number): void { console.log(`Drawing circle with radius ${radius}`); } } export namespace Rectangle { export function draw(width: number, height: number): void { console.log(`Drawing rectangle of width=${width},height=${height}`); } } } Shapes.Circle.draw(5); // Drawing circle with radius 5 Shapes.Rectangle.draw(10,20);// Drawing rectangle of width=10,height=20 ``` 上述例子展示了如何基于几何图形这一主题建立起一组相互关联却又各自独立存在的子命名空间集合。 ### 最佳实践建议 - **谨慎选用**:尽管命名空间有助于解决一些实际问题,但由于其局限性和潜在风险(如增加理解成本),除非必要否则应优先尝试其他解决方案例如ES Modules; - **合理规划**:一旦决定引入命名空间特性就要做好充分准备,包括但不限于提前构思好整体布局框架、制定清晰易懂的名字约定规则等措施以确保后续维护工作的顺利开展; - **适度运用**:即使是在适合应用命名空间的情境里也应当控制好数量范围以免过度分隔而导致难以追踪调试等问题的发生; - **文档记录**:及时更新相关说明文件以便团队成员之间共享知识经验共同进步。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一碗周.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值