我想要实现的目标
我正在尝试在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.
配置:
tsconfig.json:
declare module "IndexModule
答案 0 :(得分:1)
我终于设法得到了我想要的东西。以下是步骤和解释。
为了说明问题/解决方案,让我们以此树状为例
root
\- A
\- a1.ts
\- a2.ts
\- B
\- D
\- bd1.ts
\- bd2.ts
\- b1.ts
\- C
\- c1.ts
\- c2.ts
有一个根文件夹,包含3个其他文件夹(A,B和C):
a1.ts
和a2.ts
)bd1.ts
和bd2.ts
)和文件(b1.ts
)c1.ts
和c2.ts
)现在,如果bd1.ts
需要在a1.ts
中声明的类,我们目前会这样做..
import { ClassFromA1 } from "../../A/a1"
..使用相对路径并且难以维护(IMO)。我们将在接下来的步骤中摆脱它。
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
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
,然后我们可以从中导入所需的类而不使用相对/绝对路径。
现在可以通过以下方式进行导入..
// no matter in which file we are
import { ClassFromA1 } from "index";
import { ClassFromBD1 } from "index";
// and so on ..
..它运行良好,VisualStudio没有错误,也没有编译过程。欢迎对此解决方案发表任何评论。
干杯!