引言
在 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.ts
declare namespace Qing {
interface Person {
name: string;
age: number;
}
}
// index.ts
function createPerson(name: string, age: string): Qing.Person {return { name, age};
}
例二
// global.d.ts
export namespace Qing {
interface Person {
name: string;
age: number;
}
}
// index.ts
import {Qing} from "global.d.ts";
function createPerson(name: string, age: string): Qing.Person {return { name, age};
}
尽管下面的两个例子都没有应用 export 来导出 Person 这个类型,然而代码并没有报错,我来解释下起因:
因为在 d.ts 文件中申明命名空间时,这个命名空间申明的内容会主动默认全局可见,而无需特地应用 export 进行导出
然而某些场景下,你在不被动 export 的时候,代码会进行报错。
// utils.ts
export namespace Util {function getLength(str: string): number {return str.length;}
}
// index.ts
import {Util} from "./utils";
const str = "hello, world";
const length = Util.getLength(str);
console.log(length);
报错信息:
呈现这种状况的时候,那么就须要应用 export 将命名空间外部定义过的属性裸露进来。
// utils.ts
export 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。