【问题标题】:Create Module containing all exports in TypeScript在 TypeScript 中创建包含所有导出的模块
【发布时间】:2017-09-25 06:12:23
【问题描述】:

我想达到什么目的

我正在尝试在 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 ...
    }
}

我在很多地方(在 SO,the github repo of TypeScript,...)看到我并不是唯一一个为导入的相对/绝对路径而苦苦挣扎的人。

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

我尝试了什么

第一次尝试

这是我实际拥有的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

第二次尝试

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
}

第三次,第四次,第N次尝试

尝试declare namespaceexport module 等等……但没有运气。

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

旁注

我不是 NodeJS / 模块 / 命名空间方面的专家,所以我可能对某些东西不太了解。如果是这样,如果有人能指出我误解了什么,我将不胜感激。

Relevant link here that shows the actual problem.

配置:

  • NodeJS v7.2
  • TypeScript v2.2

tsconfig.json:

{
  "compileOnSave": true,
  "compilerOptions": {
    "removeComments": false,
    "sourceMap": true,
    "module": "commonjs",
    "target": "es6",
    "noImplicitAny": false,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "outDir": "./bin/LongiCalc"
  }
}

【问题讨论】:

  • 旁注:我想我们都可以欣赏你的帖子的努力和格式:)
  • @jhhoff02 啊,谢谢!实际上格式化帖子比写它要长;)

标签: node.js typescript module


【解决方案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,可以在我们的项目中设置:

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

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 上没有错误,也没有转译类。欢迎对此解决方案发表任何评论。

干杯!

【讨论】:

    猜你喜欢
    • 2013-05-03
    • 2022-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多