如何使 TypeScript 输出有效的 ES6 模块导入语句?

How to make TypeScript output valid ES6 module import statements?

All major browsers 支持 ES6 模块有一段时间了。

这些方法与许多服务器端方法不同,因为它们需要指定要从中导入的确切文件 - 它们不能使用文件发现。

这是有道理的——在 Node 应用程序或像 WebPack 这样的捆绑器中,他们只真正需要模块的名称,然后可以花一些额外的时间来发现保存代码的特定文件。在网络上,可能会浪费很多往返('library' in library/index.js,或 library/library.js,或 library.jsrequire() 不关心,但在网络上我们必须这样做)。

TypeScript 支持 ES6 模块(在 tsconfig.json 中设置 "module": "es6")但它似乎使用了文件发现方法...

假设我有 library.ts:

export function myFunction(...) {  ... }

然后在app.ts:

import {myFunction} from './library';
var x = myFunction(...);

然而,这在转译时没有改变 - TS 输出仍然具有用于文件发现的 'library' 名称,这是行不通的。这会引发错误,因为未找到 'library'

<script type="module" src="app.js"></script>

为了让 ES6 模块工作,TS 输出需要引用特定文件:

import {myFunction} from './library.js';
var x = myFunction(...);

如何使 TS 输出有效的 ES6 模块 import 语句?

注意:我不是询问如何使捆绑器将 TS 输出加入单个文件。我特别想使用 <script type="module">

单独加载这些文件

编译器采用模块类型标志:

--module ES2015

并且您还需要以 ECMAScript 6 / 2015 为目标...

--target ES2015

您需要模块类型和编译目标至少为 ECMAScript 2015 才能具有 "zero transformation imports"。

您的导入语句应该看起来介于两个示例之间:

import {myFunction} from './library';

补充说明

显然还有很多关于模块解析的讨论......有 TC39 specification, and the WHATWG specification - 加上 Node 目前仍然没有文件扩展......看起来 RequireJS 可能比我们所有人都活得更久想...请看:

The TypeScript thread for supporting file extensions during import transpilation(即它会添加文件扩展名吗?)。

推荐

坚持使用模块加载器,例如 RequireJS 或 SystemJS。这也意味着您的模块可以通过分别使用 UMD 或系统模块类型在浏览器和服务器之间共享。

显然,一旦 ECMAScript 讨论得出结论,就需要重新审视。

这是一个 bug in TypeScript,尽管关于是否应该修复它存在一些争论。

有一个解决方法:虽然 TS 不允许您将 .ts 文件指定为模块的源,但它会让您指定 .js 扩展名(然后忽略它).

所以在 app.ts:

import {myFunction} from './library.js';
var x = myFunction(...);

然后在 app.js 中正确输出,并且 TS 已正确找到 import 定义和绑定。

这有一个 advantage/gotcha 是 aware/careful 的:TS 只是忽略 .js 扩展名并使用通常的文件发现加载路径的其余部分。这意味着它将导入 library.ts,但它也会找到 library.d.ts 之类的定义文件或在 library/ 文件夹中导入文件。

如果您将这些文件连接到一个 library.js 输出中,最后一种情况可能是可取的,但要做到这一点,您将要查看大量嵌套的 tsconfig.json 文件(凌乱)或者可能是另一个库的预编译输出。

对于个人项目,我采用了另一种方式。因为我让 NPM 调用 shell 脚本将 index.html 复制到 /build 文件夹,所以我有 shell 脚本,然后批量重命名所有 .js 文件,使其完全没有扩展名。

我确实必须在“MIME 类型”部分通知 IIS,对于该特定站点,无扩展名文件应该具有 MIME 类型 application/javascript,但它确实有效。没有 webpack,没有 SystemJS,什么都没有。 Index.html 刚刚硬编码

    <script type="module">
      import "./app";
    </script>

这很重要,因为我使用的测试框架 jest 不喜欢我将 .js 放入打字稿导入语句中。