引言

在 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。