首页 文章

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

提问于
浏览
9

晚上好 .

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

我的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文件中实例化(此文件可被视为应用程序中的单数"entry point"),其内容包含在MyApp命名空间中:

main.ts

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

    var score: Score = new Score();

    score.init();
    ...
}

上面的代码(以及上面目录布局中显示的所有其他依赖项)编译没有问题,并且正确运行,漂亮和流畅 . 但是,在Score.ts中,我希望在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 的定义实际上位于编译输出的底部(当它应该在顶部时):

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 = {}));
...

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

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

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

1 回答

  • 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 ... 标记添加到文件中,以便编译器可以确定您希望文件顺序是什么,或者按照您希望它们出现在输出文件中的顺序手动指定命令行上文件的顺序 .

相关问题