理解没有角度的TypeScript和SystemJS

Ala*_*nut 12 module typescript systemjs typescript2.0 es6-modules

我最近一直在用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
Run Code Online (Sandbox Code Playgroud)

我的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/**/*"
  ]
}
Run Code Online (Sandbox Code Playgroud)

TypeScript编译按预期工作,没有问题.我创建了一个名为"Alerter"的简单类,其中包含以下代码:

//alerter.ts
class Alerter {
    showMessage(): void {
        alert("Message displayed.");
    }
}

export default Alerter
Run Code Online (Sandbox Code Playgroud)

和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();
};
Run Code Online (Sandbox Code Playgroud)

在我的index.html中,我只想用System.js导入这个app.js,只想从控制台调用"test"函数.但它不起作用.无论我做了什么,我根本无法访问该功能.我看到第一个console.log行正在执行,但是当我尝试从chrome控制台调用test()时,它是未定义的.

如果我从main.ts中删除"alerter"类依赖项,一切正常.因为编译后的app.js只包含console.log调用和函数定义.

这是我在index.html中的System.js调用

System.config({
    packages: {
        "components": {
            defaultExtension: "js"
        }
    }
});

System.import("components/app");
Run Code Online (Sandbox Code Playgroud)

我现在非常绝望,并认为我应该回到Jquery的日子.这很简单但不能使它工作.

mar*_*tin 9

我看到这里发生了什么.这与正确使用TypeScript export关键字和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() {
  ...
};
Run Code Online (Sandbox Code Playgroud)

然后System.import()返回一个使用模块导出对象解析的Promise,以便我们可以在test()那里调用该方法.

System.import("components/app").then(function(m) {
  m.test();
});
Run Code Online (Sandbox Code Playgroud)

这真的像你期望的那样工作.

但是,看起来您想要定义test()globaly函数.在这种情况下,您需要window自己在全局对象上定义函数:

// app.ts
function test() {
  ...
}
declare const window;
window.test = test;
Run Code Online (Sandbox Code Playgroud)

现在,您可以在导入包后随时使用它:

System.import("components/app").then(function(m) {
  test();
});
Run Code Online (Sandbox Code Playgroud)

SystemJS有多种方法可以使用全局对象进行操作,但是当导入的包具有需要解析的依赖项时,我认为没有更简单的方法可以使用它们(否则看看这个但是它不是你的用例https ://github.com/systemjs/systemjs/blob/master/docs/module-formats.md#exports).