Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/

在当前的1.70版本中,CesiumJS现在附带了正式的TypeScript类型定义!

TypeScript定义是一个长期以来被要求的特性。虽然社区已经完成了一项支持各种手动方式的工作,其中最受欢迎的是@types/cesium,但是cesium代码库的庞大规模和不断发展的特性使得手工维护成为一项永无止境的任务。官方定义文件Cesium.d.ts的数据量超过42000行,达1.9MB。

即使您不是TypeScript用户,此工作的性质也提高了CesiumJS API参考文档的正确性和完整性,并在IDE中实现了更好的intellisense支持,可以将TypeScript定义应用于推断类型,从而使整个CesiumJS社区获得了巨大的成功。

更新CesiumJS到1.70将自动利用TypeScript应用程序中的类型检查。我们使用package.json中的types字段,在大多数情况下不需要额外的配置。但是,如果直接导入单个Cesium源文件,则需要将“types”:[“cesium”]添加到tsconfig.json配置以便获取定义。如果您以前使用过@types/cesium,则可以将其移除。

来自CesiumJS团队的官方支持意味着最新和正确的定义文件将随每个版本一起发布。这也意味着TypeScript支持将作为CesiumJS GitHub存储库的一部分进行正式跟踪。如果您在使用带有TypeScript的CesiumJS时发现一个bug,请打开一个问题(issue)或更好的方法,一个pull request请求来解决它。如果您对CesiumJS/TypeScript有疑问,或者需要帮助调试您的项目,请在社区论坛(community forum)上提问。

如果您正在使用自定义的或@types/cesium,但尚未准备好切换,则可以在安装后删除Source/cesium.d.ts。然后,TypeScript工具将返回到它找到的下一组CesiumJS类型定义。

官方的类型定义文件,Cesium.d.ts记录了超过42000行的声明和文档,其大小达1.9MB。

深入了解

虽然我们很高兴终于正式支持TypeScript,但要做到这一点还需要一些努力。最初,我们探讨了3种选择:

手动维护定义文件

我们可以手动管理和维护自己的TypeScript定义文件,作为CesiumJS代码库的一部分,很可能是每个JavaScript文件都有一个单独的定义文件,使其易于管理,比如Cartesian3.js对应Cartesian3.d.ts。在技术层面这样易于实现,但对文件同步和维护性上来说,会造成较大伤害。

另外,我们不想只包含声明接口,也不想包含内联文档,这样用户就可以充分利用intellisense。这是我们最后的选择,但如果结果证明这是唯一可行的选择,那就是我们最终的选择。

移植CesiumJS到TypeScript

您可能会惊讶地听说我们实际上评估过用TypeScript重写所有CesiumJS。对于TypeScript开发人员来说,这将是一个巨大的改进,对于CesiumJS维护人员和代码库来说,这也是一个真正的胜利。除了强类型检查之外,它还将使我们快速使用现代约定,如template literals、arrow functions和async/await,由于兼容性和工具的原因,我们目前不允许在CesiumJS代码库中使用这些约定。

不幸的是,所需的努力程度和所工作量使它在短期内不会成为一个有吸引力的选择。这个选项仍然摆在桌面上,但正如我们去年所做的大规模ES6迁移一样,它需要大量仔细的规划、研究和基础设施工作才能正常进行。

使用TypeScript编译器生成定义文件

从TypeScript 3.7开始,编译器可以编译带有JSDoc注释的JavaScript代码,并为我们生成对应的类型定义文件。这种方法完全不需要手动维护.d.ts文件,而且还具有验证和改进我们自己的JSDoc注释的额外好处,因为它们需要准确才能生成正确的类型定义。不用说,这个选项对我们非常有吸引力,我们决定在一些初步的原型设计实验表明它可以工作后运行它。

实际上,我们花了几个星期的时间来研究这种方法Marco Hutter参与了大量的文档修复和源代码调整工作,以使编译器满意。早期的工作很有希望。正如预期的那样,它暴露了JSDoc注释中的错误和不一致,并在较小程度上暴露了我们修复的CesiumJS API。不幸的是,我们很快就碰壁了。

依赖TypeScript编译器意味着当它做了一些错误或意外的事情时,我们缺乏选择。虽然编译器在某些情况下使用JSDoc注释,但在许多情况下,它依赖于自己的类型推断,并且没有为我们提供重写它的方法。它还完全忽略了大部分JSDoc,比如在对象定义属性,并将所有私有下划线变量作为定义的一部分公开。这导致我们开始以我们不习惯的方式弯曲CesiumJS基础代码,只是为了让TypeScript编译器满意。我们提出了尝试修改TypeScript编译器本身的想法,但是我们必须深入研究编译器代码,我们甚至不确定维护人员会接受什么,也不知道这个过程需要多长时间。最终,我们最喜欢的解决方案变成了一场旷日持久的赌博,我们对这种方法失去了信心。

左图:UrlTemplateImageryProvider的JSDoc, 意外地添加了属性到BingMapsImageryProvider;右图:生成的BingMapsImageryProvider定义,包含了重复定义,导致编译失败。

绘图板

结果,我们对TypeScript拥有官方JSDoc支持非常兴奋,以至于完全忽略了类似的选项 tsd-jsdoc。tsd jsdoc是jsdoc的插件,它从jsdoc输出生成类型脚本定义。这使得它非常类似于TypeScript编译器方法,但提供了对生成的类型定义有了更大的自由度。

tsd-jsdoc不直接解析JavaScript,而是依赖于jsdoc生成的抽象语法树(AST)。这意味着它不受类型推断问题或缺乏JSDoc完整性的影响,这使得TypeScript编译器接近失败。如果我们可以使用JSDoc注释来表示类型,那么它就是我们希望它出现在类型定义文件中的类型。

我们已经从以前的TypeScript编译器方法的失败中学到了很多,所以我们能够相当快地完成一个可行性评估,并且我们现有的JSDoc不正确的所有问题仍然适用。事情的进展比我们想象的要快,我们知道我们找到了解决办法。

作为开发人员,有时我们过于专注于某项技术,以至于忽略了其他选择。在这种情况下,社区成员 @bampakoa去年甚至向CesiumJS和tsd-jsdoc提交了pull请求,以使它们更加兼容。我们已经知道tsd jsdoc存在,但是我们在最初的评估中忽略了它,因为我们假定了TypeScript编译器选项会更好,并且我们意外地选择性地忽视了tsd-jsdoc。

Post-processing和验证

虽然tsd-jsdoc输出是相当高质量的开箱即用,但是我们做了一些额外的后处理来进一步改进它。这包括简单的字符串操作、正则表达式查找和替换,甚至使用TypeScript编译器重写部分文件。所有这些都是作为新构建ts gulp任务的一部分发生的。如果你好奇,可以获得这些代码check out the code.。最终的结果是一个单独的Cesium.d.ts,与生成的Cesium.js模块的入口点。

除了生成输出,build-ts任务还通过使用TypeScript编译文件来验证文件。如果开发人员在JSDoc中犯了错误,比如拼错类名或引用私有或不存在的类型,那么构建过程将失败。虽然这个验证过程非常有用,但它只捕获某些类型的错误。例如,如果有人实现了一个新的ImageryProvider,但不符合正确的接口,则定义文件将编译而不出错,但TypeScript将在尝试将新类用作ImageryProvider的应用程序中发出编译错误。

我们仍在探索添加额外验证的想法,例如用TypeScript编写一些单元测试,以识别开发过程中潜在的问题区域。

JSDoc错误

我已经多次提到,基于JSDoc的方法的一个特别令人兴奋的地方是,它为我们的文档添加了另一个级别的检验和验证,使每个人都受益,而不仅仅是TypeScript开发人员。我们的文档审查过程的一大部分现在已经自动化了。我们在代码库中发现的问题可以分为以下几类:

  • 不正确或不完整的类型- 在许多情况下,我们对类型使用了非正式或不正确的名称,例如,Image实际上是HTMLImageElement,Canvas是htmlCanvaseElement。一个有趣的例子是TypedArray,它甚至不存在于规范级别,而是完整类型列表的通用术语,例如Int8Array、Float32Array等等……我们还有不完整的泛型,例如Promise而不是Promise。
  • @exports - 我们使用JSDoc的@exports标签作为最终的支撑。如果开发人员无法在生成的HTML中显示某些内容,他们可能会添加@exports,这将“正常工作”。我们将@exports用于枚举、命名空间和函数,而不是@enum、@namespace和@function标记。这导致了不正确的类型生成。实践证明我们根本不需要在代码中的任何地方使用@exports。
  • 私有类型泄露 - 公共API中引用了很多私有类型。这些私有类型不存在于HTML输出中,对于我们的文档构建步骤来说只是无声的失败。在大多数情况下,只公开私有类型是有意义的。谢天谢地,我们也有在CesiumJS中记录私有类型的习惯,因此不必编写新的JSDoc。
  • 复制粘贴错误 - 最后一种JSDoc错误是与复制和粘贴相关的重复参数条目,例如,让ImageryProvider A,声明它正在记录ImageryProvider B上的属性,等等…

下一步

一旦社区开始使用这些定义,我们希望在接下来的几个CesiumJS版本中会出现一些小问题。我们还开始开发一个我们想要探索的想法列表,比如为实体API使用的属性接口利用泛型。最终,我们依靠社区告诉我们对开发者最重要的是什么,这样我们就可以用TypeScript路线图来塑造我们的CesiumJS 。

我们还想找出一种在CesiumJS基础代码中使用TypeScript定义的方法。我们相信VSCode有一些机制可以实现这一点,但是我们还没有探索它们。如果这被证明是可行的,那么这将是一个重大的胜利,并允许通过普通JavaScript进行另一个级别的验证,更不用说让开发CesiumJS成为比现在更好的体验了。

我敢肯定,当我说我们评估用TypeScript重写CesiumJS时,很多人都振作起来了。我绝对赞成延长时间。作为评估过程的一部分,我实际使用TypeScript编译器构建了现有的JavaScript代码库,甚至将一些基本文件(如Cartesian3.js)移植到TypeScript,以了解如何进行TS/js混合开发,而不是“一次完成”迁移策略。很像ES6,移植代码是最简单的部分。预计很快就会出现GitHub issue,它将打破所有必须发生的事情,使CesiumJS的TypeScript版本成为现实;但目前还没有承诺。

致谢

我只想再次感谢社区在过去几年中帮助产生了关于TypeScript的想法和讨论,特别向@thw0rted致谢,他是第一个改进初始TypeScript类型定义的外部贡献者,在最初的pull request中提供了很多很好的反馈。最后,非常感谢我的伙伴和维护人员 Kevin Ring,他不仅提供了大量的专家知识和反馈,还让自己投入到这项工作中,并最终对代码进行了一系列改进。

作者:Matthew Amato

原文链接:https://cesium.com/blog/2020/06/01/cesiumjs-tsd/

评语:TypeScript的引入,使得CesiumJS成为更加专业的库,同时使其更易于维护。当然移植是一个痛苦的过程。

Cesium中文网交流QQ群:807482793

Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/

CesiumJS新增官方TypeScript类型定义的更多相关文章

  1. 转载 《TypeScript 类型定义 DefinitelyTyped》

    快速使用Romanysoft LAB的技术实现 HTML 开发Mac OS App,并销售到苹果应用商店中.   <HTML开发Mac OS App 视频教程> 土豆网同步更新:http: ...

  2. TypeScript 类型定义文件(*.d.ts)自动生成工具

    在开发ts时,有时会遇到没有d.ts文件的库,同时在老项目迁移到ts项目时也会遇到一些文件需要自己编写声明文件,但是在需要的声明文件比较多的情况,就需要自动生产声明文件.用过几个库.今天简单记录一下. ...

  3. TypeScript类型定义文件(*.d.ts)生成工具

    在开发ts时,有时会遇到没有d.ts文件的库,同时在老项目迁移到ts项目时也会遇到一些文件需要自己编写声明文件,但是在需要的声明文件比较多的情况,就需要自动生产声明文件.用过几个库.今天简单记录一下. ...

  4. 在 Typescript 2.0 中使用 @types 类型定义

    在 Typescript 2.0 中使用 @type 类型定义 基于 Typescript 开发的时候,很麻烦的一个问题就是类型定义.导致在编译的时候,经常会看到一连串的找不到类型的提示.解决的方式经 ...

  5. TypeScript 学习四 面向对象的特性,泛型,接口,模块,类型定义文件*.d.ts

    1,面向对象的特性一:类,继承,见上一篇博客: 2,面向对象的特性二: 泛型(generic):参数化的类型,一般用来限制集合的内容:指定只能放某个类型的元素 如下图中的尖括号中的Person,就代表 ...

  6. JavaScript 和 TypeScript 交叉口 —— 类型定义文件(*.d.ts)

    在 <从 JavaScript 到 TypeScript 系列> 文章我们已经学习了 TypeScript 相关的知识. TypeScript 的核心在于静态类型,我们在编写 TS 的时候 ...

  7. typescript 关于class属性类型定义被属性默认值覆盖的问题及解决方式

    问题来源于 React.component的第二个参数的类型定义问题,我构建了以下简化demo,方便描述问题: class P<STATE> { public state: STATE; ...

  8. 关于typescript之定义变量和数据类型那点事

    变量和数据类型 JavaScript虽说深受万千程序员喜爱,却有着对于企业大规模开发很难管理的缺陷.这时候,TypeScript的优势便体现出来.接下来,我们会先接触在TypeScript中定义变量相 ...

  9. 玩转TypeScript(2) --简单TypeScript类型

    通过TypeScript的Module和Class,TypeScript提供了相对于javaScript更加清晰的代码构造,相较于javaScript的.js满天飞的代码,用TypeScript,你可 ...

随机推荐

  1. 【科普】.NET6 泛型

    本文内容来自我写的开源电子书<WoW C#>,现在正在编写中,可以去WOW-Csharp/学习路径总结.md at master · sogeisetsu/WOW-Csharp (gith ...

  2. 再识requests

    高级用法 本篇文档涵盖了 Requests 的一些高级特性. 会话对象 会话对象让你能够跨请求保持某些参数.它也会在同一个 Session 实例发出的所有请求之间保持 cookie, 期间使用 url ...

  3. Linux使用SCP命令不使用密钥直接进行远程复制(SSH免密登录)

    假设A服务器要把文件复制到B服务器上 首先我们要在A服务器上生成密钥对 参考:https://www.cnblogs.com/pxblog/p/14396409.html 然后在把生成的密钥公钥id_ ...

  4. JAVA比较指定的两个日期

    判断指定日期是否在某个日期内 public static SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd"); p ...

  5. java源码——两种格式日期的转换

    这里要实现1981.07.30 格式和July 30.1981格式的日期的转换. 在输入时进行日期格式的识别,并且对字符串进行操作并且输出. 难点在于字符串格式的识别和月份的转换,我用了正则表达式匹配 ...

  6. 【九度OJ】题目1137:浮点数加法 解题报告

    [九度OJ]题目1137:浮点数加法 解题报告 标签(空格分隔): 九度OJ 原题地址:http://ac.jobdu.com/problem.php?pid=1137 题目描述: 求2个浮点数相加的 ...

  7. 【LeetCode】368. Largest Divisible Subset 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址:https://leetcode.com/problems/largest-d ...

  8. Masked Gradient-Based Causal Structure Learning

    目录 概 主要内容 最终的目标 代码 Ng I., Fang Z., Zhu S., Chen Z. and Wang J. Masked Gradient-Based Causal Structur ...

  9. css基础-2 div布局

    div布局 <html> <head> <title>div布局 </title> <meta charset="utf-8" ...

  10. CSS基础 元素整体透明效果(包含内容+背景及子元素)

    属性名:opacity:数字+px; 数字值取值0-1之间数字 数字值:1表示完全不透明 0表示完全透明使用后效果 html结构代码 <div class="box"> ...