【问题标题】:Using modules in Meteor.js with Typescript将 Meteor.js 中的模块与 Typescript 一起使用
【发布时间】:2015-02-04 12:30:28
【问题描述】:

伙计们,我正在尝试做一些我认为应该很简单的事情,但我一定是做错了什么。我试图在使用 Typescript 的流星应用程序中简单地拥有一个清晰的结构。

这是我的要求:

  • 所有接口在客户端和服务器端都可用
  • 某些类实现仅在服务器上可用
  • 我不想依赖文件加载顺序来让我的应用程序正常工作
  • 我需要自己的模块不与全局对象发生冲突(例如 Position 类)
  • 我需要一个用于服务器的整体包含文件,一个用于客户端和服务器,一个用于客户端(不希望在我的文件顶部包含 10 个包含)

我现在的设置是这样的

  • 服务器
    • server-book.ts
  • 客户
  • 共享
    • collections.ts
  • 定义
    • 服务器
      • include.d.ts(包括此文件夹中的所有 .d.ts 文件)
      • server-book.d.ts(书的服务器特定实现)
    • 客户
    • 共享
      • include.d.ts(包括所有 .d.ts 文件)
      • book.d.ts(书籍接口定义)
      • collections.d.ts

在我拥有的每个 .d.ts 文件中

模块 MyModule { 接口 Bla {} };

在每个定义我拥有的类的 .ts 文件中:

模块 MyModule { 导出类 MyBla 实现 Bla {}; }

为类生成的所有 .d.ts 文件都是由 tsc -d 生成的。

通过 /// 不包含 .ts 文件,而仅包含 .d.ts 文件。

现在,当我运行它时,我收到一个错误,即 MyModule 未定义:

/// /// Meteor.startup(() => { var temp = new MyModule.ServerBook(); });

错误发生在 MyModule 上。

我做错了什么?这里的正确设置应该是什么?

谢谢!

【问题讨论】:

    标签: meteor typescript


    【解决方案1】:

    我已经在我的blog 上处理了这个问题。我决定使用邪恶的eval 命令,因为它给了我使用模块的最简单的可能性,直到出现更复杂的东西。

    文件/lib/foo.ts 位于子目录中,因为它必须在Bar 之前加载。

    eval('var Hugo = (this.Hugo || (this.Hugo = {})'); // this will override the automatically emitted var Hugo and assigns it with globally defined Hugo module 
    
    module Hugo {
      export class Foo {
        foo():string {
          return 'foo'
        }
      }
    }
    

    文件/bar.ts

    /// <reference path="lib/foo.ts"/>
    eval('var Hugo = (this.Hugo || (this.Hugo = {})'); // this will override the automatically emitted var Hugo and assigns it with globally defined Hugo module 
    
    module Hugo {
     export class Bar extends Foo {
        bar () : string {
          return 'bar';
        }
      }
    }
    

    文件/test.ts

    /// <reference path="lib/foo.ts"/>
    /// <reference path="bar.ts"/>
    
    var m = new Hugo.Bar();
    console.log(m.bar());
    console.log(m.foo());
    

    here所述,对于类,解决方案更加简单:

    class ExportedClass {
        variable : int;
    } 
    this.ExportedClass = ExportedClass;
    

    【讨论】:

      【解决方案2】:

      定义文件应使用declare 关键字。如果你不使用这个关键字,你通常会得到一个错误。

      declare module MyModule {
           export interface Bla {}
      }
      

      declare module MyModule {
          export class MyBla implements Bla {
      
          }
      }
      

      还值得检查ServerBook 类是否有export 关键字(就像您的示例中的MyBla)。

      【讨论】:

      • 这行不通,因为你不能在非瞬态模块中使用声明。
      【解决方案3】:

      经过大量试验和错误,这是我目前的发现:

      在 Meteor 中使用 typescript 的“module”关键字并不好。我认为目前你不能使用它(或者解决方法对我来说太复杂了)。

      但是,您可以这样做:

      假设您有一个包 A,您想在其中定义一个要公开的 ClassToExport 类。

      class ClassToExport {
        getFoo(){
          return "foo";
        }
      }
      

      请注意你不能this.ClassToExport = ClassToExportapi.export('ClassToExport') 否则 ClassToExport 在包 A 的全局范围内将不可用,因此需要一个模块/命名空间来导出您的类,我们将在接下来看到。

      现在,为了让你的包的消费者可以使用这个类,你必须创建一个命名空间,它相当于内部模块的“模块”打字稿关键字。

      所以让我们写:

      declare var packageA; //so that the compiler doesn't complain about undeclared var
      packageA = packageA || {}; //so that this namespace can be reused for the entire package
      packageA.ClassToExport = ClassToExport; //the actual export
      

      现在,别忘了写 api.export('packageA')在包A的package.js中

      如果你有一个包 B,你想在其中使用 ClassToExport,你在包 B 中写:

      var cte = new packageA.ClassToExport();
      

      不要忘记在包B的package.js中api.use包A

      如果不想每次使用类时都写命名空间,也可以在 using 文件的顶部写上var ClassToExport = packageA.ClassToExport;

      如果你需要一个全局类只为你打包,而不导出它,那么你可以这样做:

      this.ClassToExport = ClassToExport
      

      再一次不要api.export('ClassToExport'),否则它在包中将不再可用。

      这样,我认为内部打字稿模块的功能(导出/导入)就在那里。

      【讨论】:

        【解决方案4】:

        如果你不怕 gulp 构建,我准备了一个 typescript 样板项目,它允许你在应用程序中舒适地使用 typescript,而不是依赖于包。

        https://github.com/tomitrescak/meteor-boilerplate-typescript

        【讨论】:

          【解决方案5】:

          随机的想法,扩展 Meteor 而不是 Window 怎么样。

          Meteor.yournamespace = Meteor.yournamespace || {};
          Meteor.yournamespace.myclass = new MyClass();
          

          Meteor.yournamespace.MyClass = MyClass();
          

          我认为这比直接访问窗口对象恕我直言更具侵略性。我的两分钱。

          现在你可以做Meteor.yournamespace.MyClass:P

          --编辑

          然后您可以创建一个meteor-extend.d.ts 文件并执行以下操作:

          /// <reference path="main.d.ts" />
          declare module Meteor {
              var yournamespace: any;
          }
          

          现在您可以在Meteor 之前删除&lt;any&gt;,Typescript 不会抱怨。

          【讨论】:

            猜你喜欢
            • 2015-07-24
            • 1970-01-01
            • 2015-12-27
            • 2016-11-06
            • 2021-03-08
            • 2021-08-15
            • 2020-11-26
            • 1970-01-01
            • 2015-08-02
            相关资源
            最近更新 更多