需要澄清目标和lib编译器选项

119

我发现我对目标(target)和库(lib)选项以及它们如何与源代码中支持的功能交互感到困惑。我觉得文档需要稍加改进,因此在提出问题之前在这里询问。

我天真地认为,目标指定了输出代码所需运行的JS版本(加上模块加载器)。因此,我们总是可以在源代码中使用所有高级JS功能(如对象扩展),而编译器会为我们指定的目标生成适当的代码。我认为它已经准备好了填充等,并且代码将在目标虚拟机上运行。

然而,lib选项的文档说明默认库取决于目标。但是,库会影响可用的源代码类型,因此也会影响我们可以使用的代码。因此,我们可以使用的源功能取决于目标。这不是我预期的。我应该说我的理解是,它们是具有不同API的类型定义,尽管文档并没有真正说明它们是什么。

我可以看到有些语言功能不依赖于类型,而其他一些则依赖于类型。但是,这是否是产生这种情况的原因尚不清楚。

能否请有人澄清这个问题?

第二个问题是,为什么有ES6和ES2015库,当它们通常被记录为是同一件事时。

谢谢

1个回答

200
(这开始作为一条评论,但是太长了。)
有些令人困惑,部分原因是有一些历史背景。我没有资格权威地回答这个问题,但我从 TypeScript 早期开发以来一直在关注,这是我的理解:
  • --target参数告诉编译器在编译时包含哪个库版本(例如,ES5会在使用Promise时产生编译错误,而ES6则会完全支持Promise)。此外,还会指定编译器输出的JavaScript版本(例如,ES5会将类语法向下转换,而ES6则保留原样)。
  • --lib参数是后来添加的,可以更好地控制编译时使用的库版本,而不改变输出的JS目标。例如,一个常见的问题是,您可能会为ES6库功能(如Promise)包含polyfill,但您想以ES5浏览器为目标,通过向下转换class语法。在有了--lib之前,您只能将目标设置为ES6,以避免关于Promise的编译错误,然后再使用Babel进行向下转换;或者将目标设置为ES5并提供自己的Promise类型定义,以便编译器不会报错。现在有了--lib,您只需设置--target ES5--lib ES6,编译器就不会抱怨Promise,但仍会向下转换为ES5。
  • 两个选项都不会导致TS发出任何库polyfill(例如Promise等),正如您已经发现的那样;提供正确的运行时库是您的责任。它只会发出一些向下级语言兼容性助手,例如__extends__awaiter(区别在于classasync不仅仅是可以在运行时进行polyfill的API,而是具有语法影响的语言特性)。--lib选项只是根据您知道将在运行时使用的内容获取正确的编译检查级别的方法。
  • 至于为什么同时存在ES6ES2015,那只是因为ECMAScript更改了名称,而TS将旧名称作为向后兼容的有效选项保留了下来。 :)
你会在这些TS问题中发现很多相关内容:

TSConfig参考链接:


3
感谢您提供了一份出色的答案。因此,我认为混淆的根源在于-target同时执行这两个操作,并且有些语言特性被下编译而另一些则需要库来在源代码中使用。请问需要翻译哪段内容? - Steve Lee
2
这也回答了另一个问题 - 为什么你会使用TS和Babel :) 因此,一种针对许多当前浏览器的好方法是在TS中针对ES6进行目标设置,并使用Babel将其转换为ES5。 - Steve Lee
@Aaron 在我的 TypeScript 版本中,lib.es6.d.ts 和 lib.es2015.d.ts 稍有不同。ES6 被定义为带有 dom、dom.iterable、webworker.importscript 和 scripthost 的 es2015(语言)。 - cquezel
1
@cquezel,您正在查看生成的 es6.d.ts 文件和 es2015.d.ts 文件,但是如果您使用 --target es6,则会使用 es6.d.ts,这相当于 --lib es6,dom,dom.iterable,scripthost(如文档中所述)。如果您仅使用 --lib es6,则不会获得 DOM 等。--lib es6--lib es2015 给您相同的东西。--target es6--target es2015 也给您相同的东西。 - Aaron Beall
2
“这有点令人困惑,部分原因是因为它背后有一些历史。” 现代JS总体而言。 - LJD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接