编译输出中的TypeScript依赖项未按正确顺序解析

时间:2015-12-17 22:05:27

标签: javascript typescript

晚上好。

我在一个从Typescript项目编译的Javascript输出中出现了 - 似乎 - 无意义的问题。这个问题似乎很复杂,但我会尽量简短明了。

My Typescript项目名为“MyApp”(完全面向对象,在Visual Studio 2013中开发)设置为编译为单个输出文件(main.js,ECMAScript 5),然后在浏览器中运行。没有使用模块加载软件(如AMD),我希望保持这种方式。项目中引用的所有打字稿文件(.ts)都是自动编译的,无需使用/// <reference path>手动引用它们。

我有这个文件(Score.ts),在命名空间结构的一个深层:

居于App_Script / Score.ts

namespace MyApp.App_Script {
    export class Score {
        protected tracks: MyApp.App_Script.Entities.Track[];
        ...
    }
}

命名空间结构反映了目录布局:

MyApp
|-- App_Script
|   |-- Entities
|   |   |-- Track.ts
|   |   |-- Note.ts
|   |   `-- ...
|   |-- Loader.ts
|   |-- Score.ts
|   `-- ...
`-- main.ts

Score类在main.ts文件中实例化(此文件可被视为应用程序的单一“入口点”),其内容包含在MyApp命名空间中:

main.ts

namespace MyApp {
    import Score = MyApp.App_Script.Score;

    var score: Score = new Score();

    score.init();
    ...
}

上面的代码(包含上面目录布局中显示的所有其他依赖项)编译没有问题,并且运行正常,漂亮和流畅。但是,在Score.ts中,我希望import Track类避免必须输入数十次完全限定名称:

居于App_Script / Score.ts

namespace MyApp.App_Script {
    import Track = MyApp.App_Script.Entities.Track;

    export class Score {
        protected tracks: Track[];
        ...
    }
}

此代码也会编译,并且正确而不会消除任何错误,按预期创建指定的输出文件。我的Typescript源文件中的一切似乎都很好,因为所有与Typescript相关的工作都完美无缺:没有报告语法错误,并且自动完成在导入的Track类以及所有其他代码上正常工作。

但是当在浏览器中运行时,

  

main.js:无法读取未定义的属性'Track'。

...这也就不足为奇了,因为这是指定输出Javascript文件的开头可能出现的错误(这些是非常输出中的第一行):

main.js

var MyApp;
(function (MyApp) {
    var App_Script;
    (function (App_Script) {
        var Track = MyApp.App_Script.Entities.Track; // PLEASE LEAVE
        var Score = (function () {
            function Score() {
                this.tracks = [];

                for (var i = 0; i < 4; i++) {
                    // shouldn't this be "new MyApp.App_Script.Entities.Track()"?
                    // if I rewrite it manually, it works
                    this.tracks.push(new Track());
                }
            }
            return Score;
        })();
        App_Script.Score = Score;
    })(App_Script = MyApp.App_Script || (MyApp.App_Script = {}));
})(MyApp || (MyApp = {}));
...

Track的定义实际上是在编译输出的 bottom 上(当它应该在顶部时):

main.js

...
var MyApp;
(function (MyApp) {
    var App_Script;
    (function (App_Script) {
        var Entities;
        (function (Entities) {
            var Track = (function () {
                function Track() {
                    ...
                }
                return Track;
            })();
            Entities.Track = Track;
        })(Entities = App_Script.Entities || (App_Script.Entities = {}));
    })(App_Script = MyApp.App_Script || (MyApp.App_Script = {}));
})(MyApp|| (MyApp = {}));
...

以下是我观察到的内容:如果你import一个班级,那很好(分数是从main.ts导入而没有问题)。如果import包含在其他位置导入的导出类的命名空间中的类,编译器会在不报告任何错误的情况下阻止不可用的代码。

这是TypeScript编译器中的一个错误,还是只是我遗漏的一些完全无关紧要的东西?我不希望使用模块加载系统,因为这似乎是编译器的问题,而代码在浏览器中运行。

IMO,import应该只是在编译期间用完全限定的名称替换受影响的类名,而不是在输出Javascript代码中引入其他指令。

1 个答案:

答案 0 :(得分:7)

  

这是TypeScript编译器中的错误

没有

  

或者这只是一件我完全无聊的事情?

  

我不想使用模块加载系统,

您可能应该,因为您有文件订购问题

  

import应该在编译期间简单地用受限制的名称替换受影响的类名,而不是在输出Javascript代码中引入其他指令。

这样做是错误的。考虑一下这样的代码:

namespace Z {
  export var A = 10;
}

namespace X {
  import Y = Z.A;
  namespace Q {
     let Z = { A: 20 };
     // If we replaced 'Y' with 'Z.A', as proposed, 'a' would be 20
     // when it should be 10
     let a = Y;
  }
}

这里的问题是TypeScript不会自动猜测应该连接文件的顺序。

修复方法是将/// <reference ...标记添加到文件中,以便编译器可以找出您希望文件顺序的内容,或者按照您希望的顺序手动指定命令行上文件的顺序出现在输出文件中。