创建包含TypeScript中所有导出的模块 [英] Create Module containing all exports in TypeScript
问题描述
我要实现的目标
我正在尝试在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上, TypeScript的github回购,. ..)我不是唯一一个在相对/绝对路径上苦苦挣扎的人.
我的实际问题是:是否可以创建这样的模块(或机械手),以便我可以在顶级容器中定义每个导出,并像使用NodeJS模块一样导入此容器(例如
我尝试过的事情
第一次尝试
这是我实际上拥有的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 namespace
,export module
等..没有运气.
也尝试使用declare module "IndexModule
,也会导致错误:环境模块声明中的导入或导出声明无法通过相对模块名称引用模块
旁注
我不是NodeJS/模块/命名空间的专家,所以我可能不太了解.如果是这样,我希望能有人指出我误解了.
配置: tsconfig.json:
我终于设法得到了想要的东西.这里是步骤和有关它的解释. 为说明问题/解决方案,让我们以树状结构为例 有一个根文件夹,其中包含其他三个文件夹(A,B和C): 因此,现在,如果 ..使用相对路径并且很难维护(IMO).在接下来的步骤中,我们将消除它. 所以我们要做的是在树状目录的顶部 这里是内容: 现在我们已经知道了,以前的导入可以通过这种方式完成.. ..但这仍然意味着我们使用相对路径,而不是最佳路径. 在项目中将 ..并且有效!但是问题出在编译类上,在编译后的类中,路径不会被解析为相对的. 这意味着您的
幸运的是,NodeJS具有 NodeJS中模块的解析如下(始终从 我们在这里所做的是,我们欺骗Typescript认为 它将使用上述(和链接中)描述的模式来检索 现在可以通过以下方式导入.. ..并且运行良好,在VisualStudio上没有错误,也没有编译的类.欢迎对此解决方案发表任何意见. 干杯! What am I trying to achieve I am trying to create a module in TypeScript which would contain every export of needed classes. In fact, what bothers me actually is to have Once transpiled, classes (in the produced JavaScript) with absolute paths have wrong paths (since they are not translated to relative paths, and even worse when used in conjunction with Example usage Let's start with the following hierarchy of project as example What I want to do I would like to have an So then I could do the following : I've seen in many places (here on SO, the github repo of TypeScript, ...) that I am not the only one struggling with relative/absolute paths for imports. My actual question is : Is it possible to create such a module (or mechanic) so I can define every export in a top container, and import this container as if I was using a NodeJS module (like What I tried First try This is the Second try Third, Fourth, N-th try Tried to Tried to Side note I am not an expert in NodeJS / Modules / Namespaces, so I maybe have not understood something well. If so, I would appreciate if someone can point out what I misunderstood. Relevant link here that shows the actual problem. Configuration : tsconfig.json :
I finally managed to get something like I wanted. Here are the steps and an explanation about it. To illustrate the problem/solution, let's take this arborescence as an example There is a root folder, containing 3 other folders (A, B and C) : So now, if .. which uses relative paths and is hard to maintain (IMO). We will get rid of that in the next steps. The purpose of the So what we will do, is to create this file on the top of our arborescence in a Here are the contents : Now that we have got this, the previous import can be done this way .. .. but this still implies us to use relative paths, not optimal. Setting in the project a .. and it works ! But the problem happens with transpiled classes, where paths are not resolved as relative once compiled. This means your
Fortunately, NodeJS has a The resolution of modules in NodeJS is as it follows (starting always from What we have done here, is that we tricked Typescript to think that It will use the pattern described above (and in the link) to retrieve Now imports can be done the following way .. .. and it works nicely, no errors on VisualStudio, nor transpiled classes. Any remarks on this solution is welcome. Cheers ! 这篇关于创建包含TypeScript中所有导出的模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
{
"compileOnSave": true,
"compilerOptions": {
"removeComments": false,
"sourceMap": true,
"module": "commonjs",
"target": "es6",
"noImplicitAny": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"outDir": "./bin/LongiCalc"
}
}
1.架构示例
root
\- A
\- a1.ts
\- a2.ts
\- B
\- D
\- bd1.ts
\- bd2.ts
\- b1.ts
\- C
\- c1.ts
\- c2.ts
a1.ts
和a2.ts
)bd1.ts
和bd2.ts
)和一个文件(b1.ts
)c1.ts
和c2.ts
)bd1.ts
需要在a1.ts
中声明的类,那么我们目前将.. import { ClassFromA1 } from "../../A/a1"
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"
rootDir
设置为root
文件夹可以解决此问题.. 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
策略node resolution
策略,可以将其设置为解决节点模块导入的问题.这是节点模块解析策略的真正简短摘要可以在我们的项目中设置:
.
,..
或/
=>开头,则是相对的bs1.ts
开始):
root/B/D/node_modules/index.ts
是否存在>否root/B/node_modules/index.ts
是否存在>否root/node_modules/index.ts
是否存在>是!index.ts
是NodeJS模块,并且必须将其解析为一个模块.index.ts
,然后我们可以从中导入所需的类,而无需相对/绝对路径. 4.按照我们的意愿进行导入
// no matter in which file we are
import { ClassFromA1 } from "index";
import { ClassFromBD1 } from "index";
// and so on ..
import
statements in my classes which are all relative, which is not really the best way for further maintenances. I would like to use absolute paths only.tsconfig.json
> outDir
option).root
|- helpers
|- MyHelper.ts
|- AnotherHelper.ts
|- calculators
|- MyCalc.ts
|- parsers
|- XmlParser.ts
|- JsonParser.ts
|- index.ts // currently holding export statements
index.ts
file of this kind :// 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 ...
}
}
import * as moment from "moment"
) ?index.ts
file I actually have :// 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
}
declare namespace
, export module
, etc etc .. without luck.declare module "IndexModule
too, leads to an error : Import or export declaration in an ambient module declaration cannot reference module through relative module name
{
"compileOnSave": true,
"compilerOptions": {
"removeComments": false,
"sourceMap": true,
"module": "commonjs",
"target": "es6",
"noImplicitAny": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"outDir": "./bin/LongiCalc"
}
}
1. Architecture example
root
\- A
\- a1.ts
\- a2.ts
\- B
\- D
\- bd1.ts
\- bd2.ts
\- b1.ts
\- C
\- c1.ts
\- c2.ts
a1.ts
and a2.ts
)bd1.ts
and bd2.ts
) and a file (b1.ts
)c1.ts
and c2.ts
)bd1.ts
needs classes declared in a1.ts
, we will currently do ..import { ClassFromA1 } from "../../A/a1"
2. Create an
index.ts
with all importsindex.ts
file (I named it like this, you can choose whatever name you want) is to keep all needed classes in one single file.node_modules
directory, and export every single class we need in our project. This way, we will only need the index.ts
file to retrieve the class we want.// 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"
rootDir
to the root
folder can solve this problem ..import { ClassFromA1 } from "index"
a1.js
(compiled a1.ts
file) will still have the import set as it is, but will probably be wrong because it has no knowledge of rootDir
.// a1.js
const index_1 = require("index") // supposed to be in the same package than the current file
3. Select the
node resolution
strategynode resolution
strategy that can be set to resolve node module imports. Here is a really brief summary of the Node module resolution strategy that can be set in our project :
.
, ..
, or /
=> it is relativebs1.ts
) :
root/B/D/node_modules/index.ts
exists > Noroot/B/node_modules/index.ts
exists > Noroot/node_modules/index.ts
exists > Yes !index.ts
is a NodeJS module and that it must be resolved as one.index.ts
, and from it we can then import the needed classes without relative / absolute paths.4. Do imports as we wanted to
// no matter in which file we are
import { ClassFromA1 } from "index";
import { ClassFromBD1 } from "index";
// and so on ..