理解 TypeScript 和 SystemJS 无需 Angular



我最近一直在用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文件有一个importalerter.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)。

最新更新