参考文章:
什么是命名空间
旧版本 TypeScript 中,命名空间叫作”内部模块”,新版本更名为”命名空间”,写法由module X {}
改为namespace X {}
。
命名空间是组织代码的一种手段,可以将类型、class 等封装在命名空间中,以防止环境污染,如果要让命名空间外部能访问命名空间内的成员,可以用 export 将这些成员导出。
举个例子:
namespace IM {
class Account {
id: string;
name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
}
class Session {
id: string;
type: 'P2P' | 'Team';
constructor(id: string, type: 'P2P' | 'Team') {
this.id = id;
this.type = type;
}
}
export const createAccount = (id: string, name: string) => {
return new Account(id, name);
}
}
const accountA = IM.createAccount('1', 'A');
// const accountB = new IM.Account('2', 'B'); // 由于Account没有导出,所以此处会报错
以上代码我们命名了一个名为 IM 的命名空间,其中有三个成员:
- 用户类 Account;
- 会话类 Session;
- 创建用户实例的函数
createAccount()
;
其中createAccount()
用 export 导出,使得空间外部可以访问,接着,我们可以借助const accountA = IM.createAccount('1', 'A')
创建一个 IM Account 实例,由于 Account 没有导出,故不能通过new IM.Account('2', 'B')
创建。
为什么要把 Account、Session 封装到命名空间内且不导出呢?这是为了防止全局污染,因为 Account 和 Session 是比较泛用的名词,如果不封闭处理,随时可能在上下文中冒出其他 Account 或者 Session,从而导致程序异常。
多文件中的命名空间
当应用变得越来越大时,我们需要把代码分割到多个文件中以方便维护。命名空间也支持多文件,每个文件都是一个命名空间,在主文件中通过三斜线指令(如/// <reference path="Validation.ts" />
)引入命名空间即可。
举个例子,我们先将上节写的命名空间 IM 的代码写入到 IM.ts 文件中:
namespace IM {
export interface AccountType {
id: string;
name: string;
}
export class Account {
data: AccountType;
// 只需传入用户名称即可自动生成一个Account数据
constructor(name: string) {
this.data = {
id: new Date().valueOf().toString(),
name,
};
}
}
}
然后同级目录下创建一个业务命名空间 Business,文件名 Business.ts:
/// <reference path="./IM.ts" />
namespace Business {
export interface AccountType {
id: string;
nickName: string;
phoneNum: string;
imAccount?: IM.AccountType;
}
export class Account {
data: AccountType;
constructor(_data: AccountType) {
this.data = _data;
}
}
}
以上代码通过三斜线指令引入 IM.ts,引用到的只是其中的 IM.AccountType 这个接口,可以看到业务 Account 数据中的 imAccount 即 IM 用户数据。
接着在同级目录下的主文件中写如以下代码:
/// <reference path="./IM.ts" />
/// <reference path="./Business.ts" />
const createAccount = (baseInfo: Business.AccountType) => {
const imAccount = new IM.Account(baseInfo.nickName);
const businessAccount = new Business.Account({
...baseInfo,
imAccount: imAccount.data,
});
return businessAccount;
};
const account = createAccount({
id: '1',
nickName: 'WJT',
phoneNum: '1008611',
});
console.log(account.data);
主文件同时引入 IM 和 Business 两个命名空间,然后编写了一个createAccount()函数用于根据基础数据创建业务 Account 和 IM Account,并将两者组合在一起。
使用tsc --outFile test.js test.ts
编译(可以把编译结果全部输出到一个文件中)生成 test.js 文件,运行打印结果:
{
id: '1',
nickName: 'WJT',
phoneNum: '1008611',
imAccount: { id: '1649756946688', name: 'WJT' }
}