我正在尝试在TypeScript中创建一个模块,该模块将包含所需的每个类的导出.事实上,让我感到困扰的是我的班级中的导入语句都是相对的,这实际上不是进一步维护的最佳方式.我想只使用绝对路径.
一旦被转换,具有绝对路径的类(在生成的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模块一样(如导入*作为“时刻”的时刻) )?
我尝试了什么
第一次尝试
这是我实际拥有的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次尝试
试图声明命名空间,导出模块等等.没有运气.
试图声明模块“IndexModule也导致错误:环境模块声明中的导入或导出声明不能通过相关模块名称引用模块
边注
我不是NodeJS / Modules / Namespaces的专家,所以我可能还没有理解.如果是这样,如果有人能够指出我误解的内容,我将不胜感激.
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" } }我终于设法得到了我想要的东西.以下是步骤和解释.
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.ts和a2.ts)
> B包含一个包含两个文件的文件夹(D,带有bd1.ts和bd2.ts)和一个文件(b1.ts)
> C包含两个文件(c1.ts和c2.ts)
所以现在,如果bd1.ts需要在a1.ts中声明的类,我们现在会做..
import { ClassFromA1 } from "../../A/a1"
..使用相对路径并且难以维护(IMO).我们将在接下来的步骤中摆脱它.
2.使用所有导入创建index.ts
index.ts文件的目的(我这样命名,你可以选择你想要的任何名称)是将所有需要的类保存在一个文件中.
所以我们要做的是在node_modules目录中的arborescence顶部创建这个文件,并导出我们项目中需要的每个类.这样,我们只需要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到根文件夹可以解决这个问题.
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.选择节点解析策略
幸运的是,NodeJS具有可以设置为解析节点模块导入的节点解析策略.这是一个可以在我们的项目中设置的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没有错误,也没有编译过.欢迎任何关于此解决方案的评论.
干杯!