11

问题:

我在 TypeScript 中有一个项目,它使用了几个我无法在我的计算机上访问的 API(它们存在于网络上)。代码将在本地编译良好,因为我在foo.d.ts文件中拥有所有 API,因此系统知道它们存在于某处。

但是,我想使用 NodeJS 应用程序对部分代码进行单元测试。我可以很好地将代码导入节点,但是每当我到达从定义文件导入模块的代码时,我都会收到以下错误:

Error: Cannot find module 'messages'
    at Function.Module._resolveFilename (module.js:527:15)
    at Function.Module._load (module.js:476:23)
    at Module.require (module.js:568:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (~/dev/repos/sample_typescript_fail/App.js:3:18)
    at Module._compile (module.js:624:30)
    at Object.Module._extensions..js (module.js:635:10)
    at Module.load (module.js:545:32)
    at tryModuleLoad (module.js:508:12)
    at Function.Module._load (module.js:500:3)
...

这是有道理的,因为该代码只是在本地定义的,并不存在。

我可以手动将模块注册到 NodeJS,比如

 Registry.register('messages', () => {...});

这样我就可以用polyfills编译和测试了吗?


这是一个示例应用程序

package.json

{
  "name": "sample_typescript_declare_issue",
  "version": "1.0.0",
  "description": "",
  "main": "index.ts",
  "scripts": {
    "start": "ts-node index.ts"
  },
  "author": "",
  "license": "MIT"
}

index.ts

import {App} from "./App";

console.log("Starting program");

// How do I fake "import {MessageSender} from "messages";"
// here so that I can run this node app as a test?

let app: App = new App();

console.log("Ending program");

App.ts

import {MessageSender} from "messages";

export class App {
    constructor() {
        let messageSender: MessageSender = new MessageSender();
        messageSender.sendMessage("foo!");
    }
}

node_modules/@types/messages/index.d.ts

export = Messages;
export as namespace Messages;

declare module Messages {

    class MessageSender {
        constructor();
        sendMessage(message: any): void;
    }

}

运行示例应用程序

运行npm start会给出上面的错误消息。

运行tsc *.tsc编译就好了。


我尝试过的其他事情

  1. 更新 package.json 以包含一个 bin:

    {
      "name": "sample_typescript_declare_issue",
      "version": "1.0.0",
      "description": "",
      "main": "index.ts",
      "scripts": {
        "start": "ts-node index.ts"
      },
      "author": "",
      "license": "MIT",
      "bin": {
        "messages": "./polyfills/messages/index.ts"
      }
    }
    
4

1 回答 1

2

正如您所提到的,编译工作正常 - 这只是.d.ts文件可用性的问题。

您要做的是在运行时更改模块导入,换句话说,更改 nodejsrequire函数的行为,因为

import {MessageSender} from "messages";

将在 javascript (ES6) 中转换为类似

const messages_1 = require("messages");
...
messages_1.MessageSender

要修改该行为,首先想到的是使用已弃用但仍然可用 的require.extensions对象。

在本地运行时,您必须首先注入类似

require.extensions['.js'] = (module, filename) => {
    if (filename === 'messages') {
        // then load mock module/polyfill using the passed module object
        // see (https://nodejs.org/api/modules.html#modules_the_module_object)
    }
};

医生说有更好的选择,但没有明确提及。

另一种可能性是查看诸如沙盒模块之类的项目,这应该会有所帮助(我还没有测试过)

于 2017-10-05T04:26:51.677 回答