引言
在 TypeScript 1.5 之前只反对命名空间的形式来组织代码,防止全局命名空间净化和命名抵触问题,在过后这是一种十分好的实际形式,尽管当初更举荐应用 ESModule 的形式来进行模块化地治理,然而应用 namespace 来结构命名空间的形式仍旧被应用,还是倡议大家学习下。
我这里会把过后学习和应用 namespace 时的一些纳闷列举进去,看看本人有没有不分明的点
namespace 的实现原理
间接通过代码来看实现原理
namespace Qing { interface Person { name: string; age: number; } let name = "qing"; let age = 18; function createPerson(name: string, age: number): Person { return { name, age }; }}
编译成 js 后
"use strict";var Qing;(function (Qing) { let name = "qing"; let age = 18; function createPerson(name, age) { return { name, age }; }})(Qing || (Qing = {}));
简略地解释下,就是申明了一个全局变量,而后利用函数立刻执行表达式构建了一个部分的作用域,使得内部无法访问到命名空间中的变量和函数。
export
仔细观察下面的代码其实能够发现,Qing 这个命名空间自身都拜访不到本人外部的属性了,这就有点绷不住了。本来的用意是要限度内部的拜访权限,后果连本人都拜访不了,这个时候就须要应用 export 来进行内容的导出了。
作用
咱们在应用 esmodule 来进行导出的时候常常用到 export 字段,在 namespace 中也是一样,用来导出命名空间中的属性。
namespace Qing { interface Person { name: string; age: number; } let name = "qing"; export let age = 18; export function createPerson(name: string, age: number): Person { return { name, age }; }}
编译后果
"use strict";var Qing;(function (Qing) { let name = "qing"; Qing.age = 18; function createPerson(name, age) { return { name, age }; } Qing.createPerson = createPerson;})(Qing || (Qing = {}));
咱们能够看到之前申明 age 变量和 createPerson 办法被挂在到了 Qing 这个变量下来了,这样命名空间 Qing 就能拜访到导出的属性了。
应用场景
其实官网举荐是将你想要导出的内容都应用 export 来进行导出,据我集体的看过的代码来说,有很多的代码没有对命名空间外部的属性进行导出,然而在内部却在应用。
例一
// global.d.tsdeclare namespace Qing { interface Person { name: string; age: number; }}// index.tsfunction createPerson(name: string, age: string): Qing.Person { return { name, age };}
例二
// global.d.tsexport namespace Qing { interface Person { name: string; age: number; }}// index.tsimport { Qing } from "global.d.ts";function createPerson(name: string, age: string): Qing.Person { return { name, age };}
尽管下面的两个例子都没有应用 export 来导出 Person 这个类型,然而代码并没有报错,我来解释下起因:
因为在 d.ts 文件中申明命名空间时,这个命名空间申明的内容会主动默认全局可见,而无需特地应用 export 进行导出
然而某些场景下,你在不被动 export 的时候,代码会进行报错。
// utils.tsexport namespace Util { function getLength(str: string): number { return str.length; }}// index.tsimport { Util } from "./utils";const str = "hello, world";const length = Util.getLength(str);console.log(length);
报错信息:
呈现这种状况的时候,那么就须要应用 export 将命名空间外部定义过的属性裸露进来。
// utils.tsexport namespace Util { export function getLength(str: string): number { return str.length; }}
为 getLength 这个函数后面加上 export 即可解决。
后面有说到在 d.ts 文件中不加 export 也能拜访到,那么我这里把 utils.ts 这个文件改成 utils.d.ts 文件,是不是就不须要为 getLength 函数后面增加 export?
很惋惜在 d.ts 文件中是不反对函数定义的,也就是带有具体实现的函数。
论断:
对于 ts 文件,文件中的命名空间中的内容如果想要被内部拜访到,必须要在后面加上 export。
对于 d.ts 文件,文件中的命名空间中的内容如果想要被内部拜访到,不强制要求加上 export。