乐趣区

关于typescript:浅析TypeScript中的命名空间

引言

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

退出移动版