我最近一直在用TypeScript研究和做简单的"hello worlds"。有些事情我认为我无法理解,那就是如何将System.js与TypeScript一起使用。互联网上的每一个教程或演示都是关于Angular2的,我还不想参与Angular 2。
例如,我有以下项目结构:
RootFolder
|
| _lib
| ...... ts (where .ts files are)
|
| components (where compiled .js files are)
| libraries
| ......... systemjs (where system.js is)
|
| index.html
| tsconfig.json
我的 tsconfig.json 文件看起来像:
{
"compileOnSave": true,
"compilerOptions": {
"noImplicitAny": true,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es5",
"module": "system",
"moduleResolution": "node",
"outDir": "./components"
},
"exclude": [
"node_modules",
"wwwroot"
],
"include": [
"./_lib/ts/**/*"
]
}
TypeScript 编译按预期工作,没有问题。我创建了一个名为"Alerter"的简单类,其中包含以下代码:
//alerter.ts
class Alerter {
showMessage(): void {
alert("Message displayed.");
}
}
export default Alerter
还有一个带有以下代码的app.ts(这是我的"主"应用程序文件):
//app.ts
import Alerter from "./alerter";
console.log("app.js included & executed");
function test() {
console.log("test called");
const alt = new Alerter();
alt.showMessage();
};
在我的索引中.html我只想导入这个应用程序.js带有 System.js并且只想从控制台调用"test"函数。但它不起作用。无论我做什么,我都无法访问该功能。我看到正在执行第一个控制台.log行,但是当我尝试从chrome控制台调用test()时,它是未定义的。
如果我从我的 main.ts 中删除"警报器"类依赖项,一切正常。因为编译的应用.js只包含控制台.log调用和函数定义。
这是我的系统.js索引中的调用.html
System.config({
packages: {
"components": {
defaultExtension: "js"
}
}
});
System.import("components/app");
我现在真的很绝望,我想我应该简单地回到Jquery时代。这很简单,但无法使其工作。
我知道这里发生了什么。这与TypeScriptexport
关键字和SystemJS的正确使用有关。
从您的描述中,您基本上希望使用 SystemJS 导入 JavaScript 文件,类似于仅使用<script>
标记,然后使用其全局定义的函数。
但这意味着您需要了解TypeScript如何编译文件。https://www.typescriptlang.org/docs/handbook/modules.html 的文档说:
在 TypeScript 中,就像在 ECMAScript 2015 中一样,任何包含顶级导入或导出的文件都被视为模块。
这就是你正在做的。app.ts
文件有一个import
,alerter.ts
文件有一个export
语句,因此这两个文件都将编译为模块。然后从你的tsconfig.json
我看到你使用的是system
格式(但是,这里没关系)。
模块的一个主要优点是它们不会泄漏其范围之外的任何全局对象。因此,当您调用System.import("components/app")
时,test()
函数仅存在于该模块中。但是你可以导出函数并在加载模块后调用它:
这意味着您需要先导出函数:
// app.ts
export function test() {
...
};
然后System.import()
返回一个 Promise,该 Promise 使用模块导出对象解析,以便我们可以在那里调用test()
方法。
System.import("components/app").then(function(m) {
m.test();
});
这确实如您所期望的那样工作。
但是,您似乎想要全局定义test()
函数。在这种情况下,您需要自己在window
全局对象上定义函数:
// app.ts
function test() {
...
}
declare const window;
window.test = test;
现在,您可以在导入包后随时使用它:
System.import("components/app").then(function(m) {
test();
});
SystemJS 有多种操作全局对象的方法,但我认为当您导入的包具有需要解析的依赖项时,没有任何更简单的方法可以使用它们(否则请查看此内容,但这不是您的用例 https://github.com/systemjs/systemjs/blob/master/docs/module-formats.md#exports)。