从JavaScript代码生成TypeScript声明文件外文翻译资料

 2023-03-14 07:03

从JavaScript代码生成TypeScript声明文件

关键词:JavaScript,TypeScript,动态分析,声明文件

1 介绍

JavaScript是最流行的编写web应用程序的语言。它也越来越多地用于运行在NodeJS(基于JavaScript的服务器端平台)上的后端应用程序。JavaScript之所以吸引开发人员,是因为它宽容的动态类型使他们能够非常快速地创建简单的代码片段,并在试错的基础上继续。

JavaScript从来没有打算超越脚本语言,因此,缺乏维护和移交大型代码库的功能。然而,现在开发人员用JavaScript创建大型复杂的应用程序。一些错误,比如输入错误的属性名和被误解的类型强制或意外的类型强制,会导致开发人员在调试上花费大量的时间。有足够的证据证明这样的灾祸。例如,一个JavaScript代码博客收集开发人员在JavaScript编程时遇到意外情况的经历。清单1展示了其中一些不直观的JavaScript行为。

清单1. 不直观的JavaScript行为:假值、空值vs未定义、typeof和类型强制

在使用基于类型信息的构建工具的语言中,这些行为产生的认知负荷被减轻了。这种洞察力激发了TypeScript的创建,它是JavaScript的超集,带有表达型注释。它已经成为JavaScript开发人员广泛使用的替代方案,因为它包含了有助于开发和维护大型应用程序的特性。TypeScript允许早期检测几种运行时错误,并集成代码智能工具,比如IDE中的自动补全。

尽管TypeScript有很多优点,但想让全世界在一天之内改用TypeScript是不现实的。因此,在TypeScript项目中,可以通过添加一个声明文件来描述TypeScript的API类型来使用现有的JavaScript库。DefinitelyTyped存储库已经被创建为一个社区,努力去收集流行的JavaScript库的声明文件。在编写的时候,它包含了6000多个库的声明文件。

不幸的是,DefinitelyTyped中大多数声明文件的创建和维护都是手动进行的,这既耗时又容易出错。由于TypeScript接受一个声明文件的表面值会导致错误加重。声明和实现JavaScript库之间的差异不会在编译时检测到,并导致IDE的错误行为(例如,自动完成提示)。由于TypeScript不执行任何类型的运行时检查,这些差异可能会导致意外行为和崩溃。这种经历会导致长时间的调试会议,开发人员受挫,降低工具链的信心。

1.1 方法

我们的目标是通过提供一个自动生成TypeScript声明文件的工具来改善这种情况。为此,我们依赖于从开发人员提供的示例中收集的运行时信息,这些信息是库文档的一部分。如果这些例子足够丰富,那么我们的工具链可以为库生成高质量的声明文件。这样,我们就利用了动态语言社区的最佳实践,这些实践支持示例和测试,而不是写出类型签名。

我们的dts-generate工具是探索从运行时信息生成有用声明文件的可能性的第一步。dts-generate附带了一个框架,该框架支持为发布到NPM注册中心的现有JavaScript库生成声明文件。该工具在运行时收集数据流和类型信息,以根据这些信息生成声明文件。

我们的工具的主要贡献有两方面:

  1. 我们不依赖于静态分析,这是很难良好和精确实现的。在跟上JavaScript频繁的语言更新时,它也容易出现维护问题。
  2. 我们从程序员的库文档中提取示例代码,并依靠动态分析从示例运行中提取库的类型化使用模式。

我们在运行时收集数据流信息和类型信息的代码插装实现是基于Jalangi的,这是一个可配置的JavaScript动态分析框架。

1.2 贡献

  • 一个从NPM包的文档中提取代码示例并从这些示例中收集运行时类型信息的框架。
  • 设计和实现dts-generate工具,这是一个命令行应用程序,它可以为一个包含运行时信息的NPM包生成一个有效的TypeScript声明文件。
  • 一个TypeScript声明文件的比较器,用于评估我们的框架,并在演进JavaScript模块时检测不兼容性。
  • 我们检查了DefinitelyTyped存储库中的所有6029个条目,找到了249个文档充分的NPM包,我们在这些包上运行dts-generate,并将结果与DefinitelyTyped存储库中相应的声明文件进行比较。

2 启发性例子

NPM包glob-to-regexp提供了将一个用于在shell中匹配文件名的glob表达式转换为正则表达式的功能。它每周的下载量约为990万次,有188个NPM包依赖于它。如果一个开发者创建了一个依赖于glob-to-regexp的库,TypeScript编译器和IDE就需要一个声明文件来分别为这个库执行静态检查和代码补全。使用dts-generate,我们会自动为glob-to-regexp生成一个TypeScript声明文件。我们的工具下载NPM包,运行从它的文档中提取的例子,收集运行时信息,并生成一个TypeScript声明文件。由于包的文档不够充分,我们提供了一个额外的示例来生成如图1所示的结果。接口检测正确。检测到可选参数。这个声明可以在TypeScript项目中使用:生成的文件可以在Visual Studio Code 6中正常工作。如果将来修改了glob-to-regexp包,则可以修改一个新的声明文件。我们的比较器工具可以比较新文件与前一个声明文件的不兼容性。

图1.glob-to-regexp生成的声明文件

3 TypeScript声明文件

生成的声明文件(如图1所示)描述了一个包含单个导出函数的包。模块名是通过camlization从NPM模块名派生出来的。第一个参数是字符串类型,第二个是由接口描述的可选对象。为了避免命名冲突,dts-generate创建了一个与模块名对应的命名空间。此模式是组织声明文件中声明类型的最佳实践。在这个例子中,I__opts接口是在名称空间GlobToRegexp中声明的。因此,它的使用必须像在GlobToRegexp中那样由命名空间限定。I__opts,接口的名称来源于形式参数的名称。

这个文件是编写声明文件的标准模板之一的实例:模块、模块类和模块函数。每个模板对应不同的方式来组织JavaScript库的导出。模板的选择取决于底层JavaScript库的结构:

模块中有几个导出函数,

模块类中有一个类结构,

模块函数中只有一个导出函数。

还有更多的模板,但大多数库都属于这三类之一。两个库glob-to-regexp和abs都是模块函数模板的实例。

5 评估

在为NPM包生成一个声明文件之后,我们需要评估它的质量。显然,生成的声明文件的质量很大程度上依赖于开发人员提供的示例的质量。例如,如果没有代码示例探索将访问特定属性的执行路径,那么该属性将不会出现在收集的运行时数据中,因此也不会出现在生成的声明文件中。

作为对生成文件质量的衡量,我们使用了它与DefinitelyTyped上为同一模块提供的声明文件之间的距离。换句话说,我们使用 DefinitelyTyped作为我们的基础真理,因为它是我们可以比较结果的唯一可用参考。为此,我们创建了dts-compare工具,它可以计算两个TypeScript声明文件之间的差异。

对于每个模块,我们应用dts-compare,与生成的声明文件和上传至DefinitelyTyped存储库的声明文件进行比较,如图7所示。虽然这种方法不能提供一个绝对的质量度量,但它至少给了我们一个dts-generate有用的迹象: DefinitelyTyped上的文件被认为对社区很有价值。如果生成的文件的准确性与 DefinitelyTyped上的文件的准确性相当,那么dts-generate是手工制作定义文件的可行替代方案。

图7.评估生成的声明文件

8 相关工作

动态分析技术。Trace Typing是一个评估改进型系统的框架。它包括收集JavaScript程序执行的痕迹,就像我们的系统一样。然而,他们研究的类型系统的目标与我们的有很大的不同。他们感兴趣的是用于提高运行时性能和传统编译的类型信息,提供了关于对象布局和标记测试的信息。与他们的方法相反,我们不仅观察参数和返回值的类型。此外,我们还跟踪将属性访问转化为对象需求的过程。我们没有泛化步骤来推断多态类型。

Hummingbird是一个用于在元编程存在的情况下在运行时对Ruby程序进行类型检查的系统。元程序还为生成的代码生成类型注释。调用生成的方法后,将根据实际参数类型以及生成的注释对方法体进行静态检查。该系统不涉及运行时跟踪。

Rubydust为Ruby实现了基于动态约束的类型推断。Rubydust运行一个可插装的Ruby程序,该程序收集参数的子类型约束,并返回方法和字段的类型,这与我们收集的交互非常不同。完成后,这些约束的解决方案被提出作为一个类型的程序。如果运行覆盖程序中足够多的路径,那么这些类型是合理的。Rubydust相当有效,因为Ruby的类型系统是标称的。对于JavaScript,这种方法作为(运行时)类型的效率要低得多

JSTrace通过在运行时收集信息来为JavaScript执行动态类型推断。它检查参数的运行时类型,并返回适当包装的函数的值。在我们的工作中,我们以类似的方式处理信息,从属性访问和方法调用中收集交互,并从中派生出进一步的类型约束。此外,JSTrace对对象和数组的类型执行(昂贵的)深度检查,而我们的检查比较浅,因此效率更高。

这些工作都没有解决如何获得足够的运行时信息样本的问题。我们的贡献之一是系统地揭示了README文件作为在检查下运行JavaScript代码的驱动程序。

数据类型推断。Petricek和同事描述了一种机制,可以从JSON、XML或格式的CSV输入示例中推断出数据类型。它们的实现依赖于类型提供程序,这是F#的一种元编程工具。类型提供程序在编译时读取示例输入,并将其转换为静态类型。这种方法纯粹是以数据为中心的,样本数据的形状决定了程序中什么是合法的。我们的方法分析程序对样本数据的行为,并将这些观察结果概括为一个类型。

dts-gen。TypeScript附带了dts-gen,这是一个为JavaScript库创建声明文件的工具。它的文档说明,结果打算用作开发声明文件的起点。开发人员随后需要对结果进行细化。

该工具在初始化后在运行时分析对象的形状,而不执行库。这将导致大多数参数和结果被推断为任意。

相反,我们的dts-generate工具的目的是生成可以上传到DefinitelyTyped的声明文件,而无需进一步的人工干预。在更新JavaScript代码后,开发人员需要在声明文件上做的任何数量的手工工作都会增加声明文件和实现之间的差异的风险。

TSInfer amp; TSEvolve。TSInfer和TSEvolve被表示为TSTools的一部分。这两个工具都是TSCheck的延续,TSCheck是一个用于检测声明文件和模块实现之间不匹配的工具。

TSInfer的方式与TSCheck相似。

剩余内容已隐藏,支付完成后下载完整资料


英语原文共 16 页,剩余内容已隐藏,支付完成后下载完整资料


资料编号:[596157],资料为PDF文档或Word文档,PDF文档可免费转换为Word

您需要先支付 30元 才能查看全部内容!立即支付

课题毕业论文、文献综述、任务书、外文翻译、程序设计、图纸设计等资料可联系客服协助查找。