创建包含TypeScript中所有导出的模块

时间:2017-04-27 12:34:00

标签: node.js typescript module

我想要实现的目标

我正在尝试在TypeScript中创建一个模块,该模块将包含所需的每个类的导出。事实上,让我感到困扰的是我的班级中有import个陈述,这些陈述都是相对的,这实际上并不是进一步维护的最佳方式。我想只使用绝对路径。

一旦被编译,具有绝对路径的类(在生成的JavaScript中)具有错误的路径(因为它们没有被转换为相对路径,甚至在与tsconfig.json> outDir选项一起使用时更糟糕)。

使用示例

让我们从以下项目层次结构开始,作为示例

root
|- helpers
   |- MyHelper.ts
   |- AnotherHelper.ts
|- calculators
   |- MyCalc.ts
|- parsers
   |- XmlParser.ts
   |- JsonParser.ts
|- index.ts // currently holding export statements

我想做什么

我想要一个index.ts这种文件:

// a top-level module, resolved like the `node` strategy of NodeJS module resolution
export module IndexModule {
    export { MyHelper } from "./helpers/MyHelper";
    export { AnotherHelper } from "./helpers/AnotherHelper";
    // do the same for every class in my project
}

那么我可以做到以下几点:

import { JsonParser } from "IndexModule"; // no relative nor absolute path

export class MyHelper {
    public constructor(input: any){
       var result: any = new JsonParser().parse(input);
       // work with result ...
    }
}

我在许多地方看到过(在这里,the github repo of TypeScript,...),我不是唯一一个与进口的相对/绝对路径斗争的人。

我的实际问题是:是否可以创建这样的模块(或机制),以便我可以在顶部容器中定义每个导出,并导入此容器,就像我使用NodeJS模块一样(如{{ 1}})?

我尝试了什么

首先尝试

这是我实际拥有的import * as moment from "moment"文件:

index.ts

第二次尝试

// index.ts is in the root directory of the project, it accesses classes with relative paths (but here, management is quite easy)
export { Constants } from "./helpers/Constants";
export { ConstraintCalculatorHelper } from "./helpers/ConstraintCalculatorHelper";
export { MomentHelper } from "./helpers/MomentHelper";
export { Formatter, OutputFormatterHelper } from "./helpers/OutputFormatterHelper";
// ... doing this for each class I have in my project

第三,第四,第N次尝试

尝试declare module IndexModule { export { Constants } from "./helpers/Constants"; export { ConstraintCalculatorHelper } from "./helpers/ConstraintCalculatorHelper"; export { MomentHelper } from "./helpers/MomentHelper"; export { Formatter, OutputFormatterHelper } from "./helpers/OutputFormatterHelper"; // error : Export declarations are not permitted in a namespace } declare namespace等等,没有运气。

尝试export module也导致错误:环境模块声明中的导入或导出声明无法通过相对模块名称引用模块

旁注

我不是NodeJS / Modules / Namespaces的专家,所以我可能还没有理解。如果是这样,如果有人能够指出我误解的内容,我将不胜感激。

Relevant link here that shows the actual problem.

配置:

  • NodeJS v7.2
  • TypeScript v2.2

tsconfig.json:

declare module "IndexModule

1 个答案:

答案 0 :(得分:1)

我终于设法得到了我想要的东西。以下是步骤和解释。

1。架构示例

为了说明问题/解决方案,让我们以此树状为例

root
  \- A
     \- a1.ts
     \- a2.ts
  \- B
     \- D
        \- bd1.ts
        \- bd2.ts
     \- b1.ts
  \- C
     \- c1.ts
     \- c2.ts

有一个根文件夹,包含3个其他文件夹(A,B和C):

  • A包含两个文件(a1.tsa2.ts
  • B包含一个包含两个文件的文件夹(D,bd1.tsbd2.ts)和文件(b1.ts
  • C包含两个文件(c1.tsc2.ts

现在,如果bd1.ts需要在a1.ts中声明的类,我们目前会这样做..

import { ClassFromA1 } from "../../A/a1"

..使用相对路径并且难以维护(IMO)。我们将在接下来的步骤中摆脱它。

2。创建一个包含所有导入的index.ts

index.ts文件的目的(我这样命名,你可以选择你想要的任何名称)是将所有需要的类保存在一个文件中。

那么我们要做的是在node_modules目录中的树枝顶部创建此文件,并导出我们项目中所需的每个类。这样,我们只需要index.ts文件来检索我们想要的类。

以下是内容:

// current position : root/node_modules/index.ts
export { ClassFromA1 }  from "./A/a1.ts"
export { ClassFromA2 }  from "./A/a2.ts"
export { ClassFromBD1 } from "./B/D/bd1.ts"
export { ClassFromBD2 } from "./B/D/bd2.ts"
export { ClassFromB1 }  from "./B/b1.ts"
export { ClassFromC1 }  from "./C/c1.ts"
export { ClassFromC2 }  from "./C/c2.ts"

现在我们已经得到了这个,之前的导入可以这样做..

import { ClassFromA1 } from "../../index"

..但这仍然暗示我们使用相对路径,而不是最佳路径。

在项目中设置rootDirroot文件夹可以解决此问题。

import { ClassFromA1 } from "index"

..它的确有效!但问题发生在已编译的类中,其中路径在编译后不会被解析为相对的。

这意味着您的a1.js(已编译的a1.ts文件)仍然会按原样设置导入,但可能会出错,因为它不知道rootDir

// a1.js
const index_1 = require("index") // supposed to be in the same package than the current file

3。选择node resolution策略

幸运的是,NodeJS有一个node resolution策略,可以设置它来解析节点模块导入。这是一个可以在我们的项目中设置的really brief summary of the Node module resolution strategy

  • 检查导入路径
  • 如果导入路径以.开头,../ =>它是相对的
  • 如果导入路径以name =>开头它是一个节点模块(这很重要

NodeJS中模块的解析如下(始终从bs1.ts开始):

  • 检查root/B/D/node_modules/index.ts是否存在>否
  • 检查root/B/node_modules/index.ts是否存在>否
  • 检查root/node_modules/index.ts是否存在>是的!

我们在这里做的是,我们欺骗Typescript认为index.ts是一个NodeJS模块,并且必须将其解析为一个。

它将使用上面描述的模式(并在链接中)来检索index.ts,然后我们可以从中导入所需的类而不使用相对/绝对路径。

4。做我们想要的进口

现在可以通过以下方式进行导入..

// no matter in which file we are
import { ClassFromA1 } from "index";
import { ClassFromBD1 } from "index";
// and so on ..

..它运行良好,VisualStudio没有错误,也没有编译过程。欢迎对此解决方案发表任何评论。

干杯!