深圳幻海软件技术有限公司 欢迎您!

TypeScript 遭库开发者嫌弃:类型简直是万恶之源

2023-02-28

在今年《2022前端开发者现状报告》中显示,84%受访者表示使用过TypeScript,可见这门语言已被越来越多的前端开发者所接受。他们表示,TypeScript让Web开发变得轻松——不用在IDE和浏览器之间来回多次切换,来猜测为什么“undefinedisnotafunction”。然而,本周r

在今年《2022 前端开发者现状报告》中显示, 84% 受访者表示使用过 TypeScript,可见这门语言已被越来越多的前端开发者所接受。他们表示,TypeScript 让 Web 开发变得轻松——不用在 IDE 和浏览器之间来回多次切换,来猜测为什么“undefined is not a function”。

然而,本周 redux-saga 的工程师 Eric Bower 却在一篇博客中提出了不同意见,他站在库开发者的角度,直言“我很讨厌 TypeScript”,并列举了五点理由。这篇博客发布后,随即引发了赞同者和反对者的激烈讨论,其中,反对者主要认为文中的几点理由只能作为开发人员的意见,而且并没有提供证明实质性问题的具体例子。

redux-saga 是一个 库(Library),具体来说,大部分情况下,它是以 Redux 中间件的形式而存在,主要是为了更优雅地管理 Redux 应用程序中的副作用(Side Effects)。

以下为 Eric 原文译文:

作为端开发者,其实我挺喜欢 TypeScript,它大大削减了手动编写自动化测试的需求,把劳动力解放出来投入到更能创造价值的地方。总之,任何能弱化自动化测试工作量的技术,都是对生产力的巨大提升。

但从库开发的角度来看,我又很讨厌 TypeScript。它烦人的地方很多,但归根结底,TypeScript 的原罪就是降低库开发者的工作效率。从本质上讲,TypeScript 就是把复杂性从端开发者那转移给了库开发者,最终显著增加了库开发流程侧的工作负担。

说明文档

端开发者可太幸福了,TypeScript 给他们准备了完备的说明文档和博文资料。但在库开发者这边,可用的素材却很少。我能找到的最接近库开发需求的内容,主要集中在类型操作上面。

这就让人有种强烈的感觉,TypeScript 团队觉得库开发者和端开发者并没什么区别。当然有区别,而且很大!

为什么 TypeScript 的网站上没有写给库开发者的指南?怎么就不能给库开发者准备一份推荐工具清单?

很多朋友可能想象不到,为了在 Web 应用和库中找到“恰如其分”的类型,我们得经历怎样的前列。对端开发者来说,Web 应用开发基本不涉及条件类型、类型运算符和重载之类的构造。

但库开发者却经常跟这些东西打交道,因为这些构造高度动态,会把逻辑嵌入到类型当中。这就让 TypeScript 调度起来令人头痛万分。

调试难题

库开发者是怎么对高度动态、大量使用的条件类型和重载做调试的?基本就是硬着头皮蛮干,祈祷能顺利跑通。唯一指望得上的,就是 TypeScript 编辑器和开发者自己的知识储备。换个类型,再看看最终结果,如此循环往复。据我所知,大家似乎都是在跟着感觉走,并没有任何稳定可靠的科学方法。

对了,库开发者经常会用到 TypeScript playground,用来隔离掉类型逻辑中那些离散的部分,借此找出 TypeScript 解析为某种类型的原因。Playground 还能帮助我们轻松切换 TypeScript 的版本和配置。

但这还不够,远远不够。我们需要更称手的生产工具。

太过复杂

我跟 redux 打过不少交道,redux-toolkit 确实是个很棒的库,开发者可以用它查看实际代码库中的类型是如何正确完成的。而问题在于,虽然它能把类型搞得很清楚,但复杂度也同样惊人。

  1. createAction #1
  2. createAction #2

这还只是一例,代码库中充斥着更多复杂的类型。此外,大家还要考虑到类型和实际代码数量。纯从演示出发、忽略掉导入的代码,该文件中只有约 10% 的代码(在全部 330 行中只占 35 行)能被转译成 JavaScript。

编码指南经常建议开发者不要使用嵌套三元组。但在 TypeScript 中,嵌套三元组成了根据其他类型缩减类型范围的唯一方法。是不是闹呢……

测    试

因为可以从其他类型生成类型,而且各类型都有很高的动态特性,所以任何生产级别的 TypeScript 项目都得经历专门的一类测试:类型测试。而且单纯对最新版本的 TypeScript 编译器进行类型测试还不够,必须针对以往的各个版本全部测试。

这种新的测试形式才刚刚起步,可用工具少得可怜,而且相当一部分要么被放弃了、要么只保持着最基本的维护。我之前用过的库有:

  1. DefinitelyTyped-tools
  2. sd
  3. dtslint (moved)
  4. typings-checker (deprecated)

看得出来,类型测试工具的流失率很高。而且因为难以迁移,我有些项目直到现在还在使用早就被弃用的库。

当然,其中的 dtslint 和 tsd 算是相对靠谱,但它们互为补充、而非择一即可。为什么我们需要两款工具才能完成同一类工作?这个问题很难回答,实际使用体验也是相当难受。

维    护

类型会给库添加大量代码。在初次为某个项目做贡献时,首先需要了解应用程序逻辑和类型逻辑,这直接就让很多打算参与的朋友望而却步了。我就帮忙维护过 redux-saga,项目近期发布的 PR 和 issue 主要就集中在类型身上。

我发现相较于编写库代码,我花在类型调整上的时间要多得多。

我精通 TypeScript,但还没到专家那个水平。在经历了几年的 TypeScript 编程之后,作为一名库开发者,我还是觉得自己用不明白 TypeScript。所以,精通好像成了 TypeScript 的准入门槛。这里的万恶之源就是类型,它让 js 库维护变得困难重重,断绝了后续开发者的贡献参与通道。

总   结

我认可 TypeScript 的成绩,也钦佩它背后的开发团队。TypeScript 的出现彻底改变了前端开发的格局,任何人都不能忽视这份贡献。

但作为库开发者,我们需要:

  1. 更好的说明文档。
  2. 更好的工具。
  3. 更易用的 tsc。

不管怎么说,靠研究 TypeScript 编译器源代码才能搞清楚一段代码为什么会被解析成特定类型,也实在是太离谱了。