【问题标题】:How can I avoid always having to import my own code in Typescript?如何避免总是必须在 Typescript 中导入自己的代码?
【发布时间】:2018-06-06 21:14:45
【问题描述】:

所以我最近正在研究一个大型 Typescript 项目 (https://github.com/BabylonJS/Babylon.js),我注意到他们不需要导入任何东西,他们只需使用他们的命名空间,其余的就是(看似)魔法。

这让我想到我想为自己使用类似的东西,所以我开始了一个简单的打字稿项目来尝试一下。

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "src",
    "outFile": "server.js"
  }
}

src/main.ts

module Test {
  console.log('Main started')
  const server:Server = new Server()
}

src/Server.ts

// import * as http from 'http'

module Test {
  export class Server {
    constructor() {
      console.log('Server initialized')
    }
  }
}

如果我构建这个 Typescript 项目,那么我会得到如下输出:

// import * as http from 'http'
var Test;
(function (Test) {
    var Server = /** @class */ (function () {
        function Server() {
            console.log('Server initialized');
        }
        return Server;
    }());
    Test.Server = Server;
})(Test || (Test = {}));
var Test;
(function (Test) {
    console.log('Main started');
    var server = new Test.Server();
})(Test || (Test = {}));

到目前为止,一切都很好。问题是我想利用一些外部模块,在这种情况下是 http 模块,所以我取消了上面的导入行,现在 Typescript 报告:

src/server/Server.ts(1,1): error TS6131: Cannot compile modules using option 'outFile' unless the '--module' flag is 'amd' or 'system'.

Node 使用 commonjs 模块系统,因此显然设置这些标志中的任何一个都不会对我有太大帮助。我仍然尝试过它们以及其他各种标志组合,但无济于事。我注意到 BabylonJS 并没有真正使用这样的外部导入,而是选择将它们声明为外部并在执行时将它们作为脚本标签全局提供。有没有类似 Node 的东西?

【问题讨论】:

  • module 语法已弃用,typescriptlang.org/docs/handbook/modules.html。出于多种原因,最好显式地导入内容。使用 outFile 唯一明显的好处是您可以跳过捆绑,这与 Node 应用程序无关,因为它自然使用不需要进一步捆绑的 CommonJS 模块。
  • 有趣的是编译器没有提到这一点,但似乎namespace 关键字是等效的并且仍然受支持。我正在使用outFile,因为否则每个输入的打字稿文件都会被翻译成一个输出的 Javascript 文件,然后它们必须全部执行或捆绑起来才能工作。如果有一个构建工具可以帮助支持我感兴趣的配置,那么我愿意接受建议!
  • 那么它们必须全部执行或捆绑起来才能工作 - 这就是通常的做法。您将它们编译到 dist 文件夹并作为常规 Node js 应用程序执行。不需要捆绑。您可以使用 ts-node 透明地执行此操作。
  • 很抱歉给您带来了困惑。我的意思是他们必须进一步处理才能工作。使用outFileServer.ts 的内容被连接起来并在main.ts 的内容之前运行,所以一切正常。使用outDir 会有单独的文件,运行main.js 是不够的。
  • 它是 Node 应用程序,不是吗? import 语句被转译为 require,因此如果您明确声明模块依赖关系,则运行入口点就足够了。

标签: node.js typescript commonjs


【解决方案1】:

你不能同时拥有这两个东西,即

如何避免总是在 Typescript 中导入我自己的代码?

我想利用一些外部模块

您只能通过不使用外部模块来避免导入,结果将是一个巨大的脚本文件,它只能将外部依赖项用作通过script 标签加载的脚本创建的全局变量,正如您已经注意到的。

当您执行此操作时,该语言不允许您使用外部模块。如果您在顶层导入了外部模块,则您的文件将成为一个模块,并且如果不导入它们,它就无法使用其他文件中的代码。 AFAIK 不允许在命名空间内导入外部模块。

也就是说,我不认为你的问题 - “我怎样才能避免总是必须在 Typescript 中导入我自己的代码?” - 有一个有效的前提。 CommonJS 模块系统是防止大型项目变得无法维护的混乱的解决方案。如果项目的某些部分是您自己的代码或某些外部依赖项,则无关紧要 - 如果它是具有良好定义接口的单独部分,则应将其打包并作为模块使用。

【讨论】:

  • 回答您的评论:如果我的项目具有很少的外部依赖项和许多经常在许多文件中重用的代码(例如 Vector<T>),那么我似乎明智的做法是具有隐式自我访问的公共名称空间中的所有内容。例如,这在 C# 中运行良好,但在实践中看到它之前,我从未考虑过将它与 Typescript 一起使用。
  • CommonJS 中有一个共同的命名空间,它叫做global object - 你可以分配给global.Vector,并在任何地方使用它作为global.Vector,你甚至可以编写环境类型声明来添加Vectorglobal,将其放在单独的文件中,并将该文件包含在 tsconfig.json 中。这样你就可以以类似于 C# 的方式使用它,但我认为这不是在 node.js 中做事的正常方式。
【解决方案2】:

对我有用的解决方案是这样的:

Server.ts

declare var http: any;

namespace Test {
  export class Server {
    constructor() {
      console.log('Server initialized')
      const server = http.createServer()
      server.listen()
    }
  }
}

然后我只需在运行时提供http,例如在输出前添加var http = require('http')。感谢 artem 朝着正确的方向轻推。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-03
    • 1970-01-01
    • 2018-11-11
    • 1970-01-01
    • 2023-02-11
    • 1970-01-01
    相关资源
    最近更新 更多