如何在使用NodeJS目标的TypeScript中正确使用模块和接口?

我和我的团队是TypeScript和NodeJS的新手,我们遇到了一些严重的麻烦,使得这个项目变成了现实。 这意味着要成为一个模块化的游戏资产pipe道,使用TypeScript编写,与NodeJS一起使用(我没有参与到这里的决策中,讨论仍在进行中,但我们仍然需要一个原型)。

我们已经对这个架构有了一个很好的想法,但是甚至很难让原型运行起来,因为我似乎无法将模块与接口和外部依赖相结合。 我们的某些组件还需要使用NodeJS或其他库模块(例如NodeJS.fs用于读取/写入文件),我们希望能够使用///reference来添加适当的d.ts文件以保持types在开发时安全。

假设的项目结构的一个例子是:

 /pipeline /log - ILog.d.ts - StdOutLog.ts - FileLog.ts - ... /reader - IReader.d.ts - TextReader.ts - ... /parser - IParser.d.ts - XmlParser.ts - JsonParser.ts - ... /task - ITask.d.ts - JsTask.ts - CliTask.ts - ... /... 

我们希望使用它的方式是我们为接口提供默认实现(以涵盖基本的内容,例如运行控制台命令,logging到文件或stream,读取JSON和XMLconfiguration等),以及接口本身,以便其他团队可以创build自己的扩展(例如class GitTask extends CliTask封装存储库操作,或class JpgReader implements IReader )。

在调用方面,在一个不同的项目/亚军应用程序,它应该像这样工作:

 import pipeline = require('pipeline'); //... var log = new pipeline.log.FileLog(); log.info("filelog started"); var parser = new pipeline.parser.XmlParser(); parser.parse(somexmldata); log.info("parsing XML"); // ... 

我很可能只是做错了(tm),但是我觉得用TypeScript做我们想要做的事情是不容易的,特别是考虑到例如日志组件的定义可以很容易地有几个接口,并且枚举工厂,logging器,logitem,日志目标,日志级别)。 据我所知,NodeJS模块需要是一个单一的JS文件,但即使使用一个单一的import将您的模块变成一个外部模块,这些不会再编译成单个文件,所以这似乎是一个非常陡峭的路障我。

有没有一种方法来实现TypeScript目标NodeJS的结构化和预期用法? 如果是的话,这些文件需要看起来像什么(尤其是关于模块层次结构和组件FQN,例如pipeline.log.X,pipeline.task.Y等;我将如何正确使用moduleexport它)? 如果不是,有什么合适的替代scheme来实现我们的目标?


[更新]我已经根据basarat的build议重构了我的原型,它已经看起来比以前好多了。 不过,使用另一个类时遇到了编译错误:

 error TS2095: Could not find symbol 'LogItem'. 

LogItem/log定义的类,由StdOutLog.ts在同一个文件夹中使用。 IntelliJ给了我多个定义(显然,一个是LogItem类本身,另一个是在/log的索引文件中导出的)。 我试过使用模块符号log.LogItem ,但没有奏效。 将全部默认实现文件添加到全局声明文件也不起作用。 [/更新]

[Update2]下面是错误发生地点的更多代码。 只有在运行grunt-ts任务时,我才会在IntelliJ中得到任何错误/标记。

// src / log / LogItem.ts:

 ///<reference path='../pipeline.d.ts'/> class LogItem implements ILogItem { // ... constructor(level:LogLevel, message:string) { // ... } public static create(level:LogLevel, message:string):ILogItem { return new LogItem(level, message); } // ... } export = LogItem; 

// src / log / Log.ts:

 ///<reference path='../pipeline.d.ts'/> class Log implements ILog { // ... private getLogItem(level:LogLevel, message:string):ILogItem { return LogItem.create(level, message); // <-- that's where I get the "symbol not found" error } // ... } export = Log; 

// src / pipeline.d.ts:

 ///<reference path="../typings/node/node.d.ts" /> //grunt-start /// <reference path="pipeline.ts" /> /// <reference path="log/Log.ts" /> /// <reference path="log/LogFactory.ts" /> /// <reference path="log/LogItem.ts" /> /// <reference path="log/StdLogEmitter.ts" /> /// <reference path="log/log.d.ts" /> /// <reference path="log/log.ts" /> /// <reference path="parser/JsonParser.ts" /> /// <reference path="parser/parser.d.ts" /> /// <reference path="parser/parser.ts" /> //grunt-end 

[/ UPDATE2]

引用全局.d.ts文件中的所有.d.ts文件,该文件具有///<reference标记到所有单个引用+ vendor.d.ts (例如node.d.ts )文件。

 /pipeline /globals.d.ts /log - ILog.d.ts - StdOutLog.ts - FileLog.ts - ... /reader - IReader.d.ts - TextReader.ts - ... /parser - IParser.d.ts - XmlParser.ts - JsonParser.ts - ... /task - ITask.d.ts - JsTask.ts - CliTask.ts - ... /... 

这可以防止您经常引用.d.ts文件。

现在每个XmlParser.ts文件都会导出一些类,例如XmlParser.ts

 /// <reference path='../globals.d.ts'/> class XMLParser implements IParser{ } export = XMLParser; 

每个文件夹也有一个index.ts ,导入和导出该文件夹中的所有类外部模块样式:

 export import XmlParser = require('./xmlParser'); // so on 

相同的一级( pipeline/index.ts ):

 export import parser = require('./parser/index'); 

现在,如果你导入pipeline / index.ts你的代码将按预期工作:

 import pipeline = require('./pipeline/index'); var parser = new pipeline.parser.XmlParser(); parser.parse(somexmldata); log.info("parsing XML"); 

注意:Grunt-ts可以为您创build这些import / export语句,以便您不必担心文件path: https : //github.com/grunt-ts/grunt-ts/issues/85