新Blub悖论,或者说:为什么TypeScript在AI时代是一个糟糕的选择

Lobsters Hottest 新闻

摘要

认为TypeScript由于不健全的类型系统而成为AI时代的一个糟糕默认选项,它无法捕获AI生成的代码中的错误,并将其比作Paul Graham的Blub悖论。

<p><a href="https://lobste.rs/s/5vxj6l/new_blub_paradox_why_typescript_is_poor">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/06/26 18:11

# 新 Blub 悖论,或曰:为什么 TypeScript 是 AI 时代的糟糕选择 来源:https://www.iankduncan.com/engineering/2026-06-26-the-new-blub-paradox 在一个多语言代码库中,哪种语言应该成为默认选项?就是当没有人刻意去论证另一种语言时,你会自然选择的那种。过去,这是一个直截了当的计算:招聘、生态系统、团队已经掌握的技能。但最近,一个新的理由挤进了这个混合体:默认选择 AI 写起来最好的语言。而对许多团队来说,显然就是 TypeScript。 我认为这个推理是一个穿了新衣的二十五年之久的错误。 需要明确范围:如果你交付的是任何需要在浏览器中运行的东西,你实际上无法避开 TypeScript,假装不是这样是愚蠢的。也有真正的理由刻意选择它——比如一个已经深耕在其中的团队、一个你实际需要的库生态、一个无处可去的前端。我的争论点不在于在合适的地方使用 TypeScript,而是基于“AI 喜欢它”这个理由,让它成为所有事物的未经审视的默认选项。在其他大多数方面,我发现它相当薄弱,这就是我想要阐述的观点。 ## 旧悖论 二十五年前,Paul Graham 写道,你对语言的选择是一种竞争武器。他的创业公司赢了,他认为,部分原因在于他们用 Lisp 编写,而竞争对手则在 C++ 和 Perl 中苦苦挣扎。Blub 悖论:一个精通中等语言的程序员能够识别出所有比他使用的语言更弱的语言,但天生就无法看到更强大的语言。从 Blub 内部看,更富表达力的语言只是看起来奇怪且不必要。 我们正在重新学习这一课,只不过现在的压力不再是同行的舒适度或招聘池,而是 AI。而许多人似乎正在定居的语言,即新的 Blub,公认的合理中间态,就是 TypeScript。 在 LLM 时代,TypeScript 的宣传很有诱惑力,因为它听起来像是一个双赢而非屈服。你不是完全放任自流的动态语言牛仔。你有类型!模型在这方面极其出色,因为它们消化了 GitHub 上的每一行代码。这是明智的中心:有足够的结构来感觉有纪律,有足够的语料来让自动补全流畅。你为什么要选择更奇特的东西呢? 原因如下。TypeScript 在最关键的维度上恰恰是两方面的最差组合。AI 时代将其核心设计妥协(即一个为了简化 JavaScript 集成而设计的非健全类型系统)从一个小怪癖变成了一个负担。 ## 故意不健全 TypeScript 的类型系统在设计上就是不健全的。所谓不健全,是指它允许在运行时出现类型错误。这不是一个 bug 或未完成的角落。这是一个明确的目标。团队会直接告诉你,他们选择允许运行时类型错误,以换取实用性和 JavaScript 兼容性。`as` 断言让谎言通过检查器的审查。`any` 是地板上的一个洞,而且具有传染性;一个上游的 `any` 很容易导致整个调用链失去它们试图强制执行类型级别保证的能力。数组索引返回一个 `T`,却在运行时愉快地返回 `undefined`。对象的键比其类型声明的要多,而且根据对象的来源(例如从 JSON 解析的对象),可能并不具有声明的键。那个本应检查模型工作的编译器,根据其自身的章程,已经同意在一旦不方便的情况下就视而不见。 现在把这个放到一个机器生成大量看似合理但你并未编写也不会完全阅读的代码的世界里。真正在捕捉模型错误的是什么? 在一个健全的类型系统中,很大一部分看似合理的错误根本不会编译通过。你编码的不变量禁止了它们,无一例外,在每次构建时,几秒钟内,且不会有人感到疲倦。这是你拥有的最便宜、最可扩展的错误修正,当生成速度提高时,它的价值也会上升,因为你的审查者和测试套件不会随着模型扩展,但编译器会。 从根本上说,TypeScript 给你的是机器检查的安全性外观,而非保证。你从 TypeScript 编译器得到的那绿色勾号表示生成的代码通过了类型检查;然后你部署到生产环境,运行时却报错 `cannot read property 'x' of undefined`。在手写的代码库中,你可能会内化薄弱之处在哪里。在生成的代码库中,你信任的是一个正式保留了自己犯错权利(指 TypeScript 编译器在某些场景下仍可能漏掉类型错误)的检查器,应用于一个也被允许犯错的东西所编写的代码,而你却把这种组合称为“类型安全”。 与此同时,当前的 LLM 非常擅长生成通过类型检查但却微妙错误的 TypeScript 代码,因为训练语料中充满了这种东西。它知道每一个让检查器满意的惯用法,包括逃生舱口。要求一些棘手的东西,然后看看它多么轻易地就用 `as unknown as T` 或一个随意的 `any` 来让红色波浪线消失。LLM 已经学会了目标是让 `tsc` 通过,而 TypeScript 提供了丰富的词汇来让 `tsc` 通过,却不编写正确的代码。你得到了一个自信的代码生成器,它清除了一个专门设计为无需正确性即可通过的栏。 除此之外,TypeScript 对任何它自己不编译的库的看法都来自 `\.d\.ts` 文件:一个关于 JavaScript 的手写声明,而没有任何东西对照实际代码检查它。这是一个没有实现来锚定现实性的类型注解,通常由非库作者的人编写,针对的版本后来已经改变。编译器将这个未经证实的断言视为事实。根据我的经验,这些声明通常不精确或完全错误:一个可为空的返回类型被标注为非空;一堆 `any` 覆盖任何尴尬的地方;一个对象形状缺少运行时实际返回的字段;一个 `@types` 包覆盖了 v3 但版本界限有错误,而你已经安装了 v5。 现在把这个交给模型。它根据这些声明构建了对库的理解,生成完全满足它们的代码,然后编译器祝福了结果。你有一个不可靠的叙述者,阅读一份未经证实的映射,由一个同意不深究的检查器来裁判。三个“大概没问题”的层级堆叠成一个单一的绿色勾号。 比较一下一个健全且富有表现力的语言在同样循环中的表现。当你让非法状态不可表示并实际强制执行它(没有静默降级保证的逃生舱口),模型的看似合理的错误就会碰壁。类型也是上下文:一个精确的签名对函数必须做什么施加了远比 TypeScript 的结构化汤更加严格的限制——在 TypeScript 中任何形状合适的对象都能通过,而 `any` 则完全消解了约束。编译器的反馈是模型会据此行动的一个修正信号,而在一个健全的系统中,该信号实际上是有意义的。人们称之为“对 AI 困难”的语言,往往是在进入循环后赋予 AI 最大杠杆的语言,因为它们将 TypeScript 保留为隐式、可选或可断言掉的含义前置加载了。 因此,真正的比较不是“TypeScript,安全明智的中间派”与“某种可怕学术语言”。而是“一个擅长生成代码以满足一个设计成无需正确性即可通过的检查器的模型”与“一个其看似合理错误会被健全编译器实际拒绝的模型”。TypeScript 在细节上拒绝执行它看起来在执行的规则。当人类编写并阅读每一行代码并在脑海中携带不健全的缺口时,这是一个可容忍的交易。但当人类在循环中被代码的浪潮淹没时,这是一个糟糕的交易。 我在这里稍微偏离一下类型检查的考虑,来讨论安全性。TypeScript 没有自己的供应链。它编译成 JavaScript,在某个 JS 运行时上运行,并从同一下载源安装。无论你对 npm 的看法如何,一旦选择了 TypeScript,你就签下了它的一切。而 npm 是软件中被攻击最激烈、最广泛的包生态系统。Sonatype 的 2026 年报告统计,2025 年有超过 454,600 个新的恶意开源包,使累计总数超过 120 万,同比增长 75%。这不是一个糟糕的年份;追踪此事的人明确指出,在 AI 时代的黎明,这是新的基线。 这些也不都是愚蠢的 CVE,不太可能引起真正问题。2025 年 9 月,一次单一的钓鱼攻击攻破了 18 个广泛使用的 npm 包,这些包每周有超过 26 亿次下载,注入了在浏览器中重写加密货币交易的代码。几天后出现了 Shai-Hulud,这是该注册表第一个真正自传播的恶意软件:它窃取维护者令牌,利用它们访问更多账户,扫描更多秘密,并将自身重新发布到更多包中,无需人工干预即可循环。其核心机制是恶意安装后脚本:在感染包被部署时立即执行的任意代码。同年秋天,另一项独立攻击将超过 5,500 个私有仓库转为公开,最终攻破了 526 个包。 这就是我目前看到的“AI 在 TypeScript 上如此流畅”的论点未能考虑的东西。流畅性来源于庞大的语料,而同样庞大的规模(npm 作为软件宇宙中心的引力)正是使其成为攻击者最丰富目标的原因。你无法在不承担爆炸半径的情况下获得语料。而健全的类型系统,我一直在捍卫的唯一直正优势,在这里毫无帮助。健全性验证你的代码在内部是一致的。它对于你刚刚安装的依赖是否在秘密运行 TruffleHog 来获取你的环境变量一无所知。 所以当你选择 TypeScript 来让模型开心时,你选择的不是一种语言。你选择的是一个注册表、一个运行时和一个攻击面:那个拥有工业化、自复制恶意软件和每年增长四分之三的投毒包数量的攻击面。将你的安全性与被攻击最频繁、最自动化、最有创意的生态系统捆绑在一起,无论 LLM 写 TypeScript 有多好,这都是一场糟糕的赌注。 最后还有一个几乎戏剧性的转折。安全研究人员评估认为,最近的 npm 蠕虫本身很可能是 AI 辅助编写的,证据是恶意脚本中特有的注释和表情符号。那种被推销为留在这个生态系统的理由的生成流畅性,正在被用来攻击它。代码生成的水管两头都有水。 我想小心不要过度推销替代方案,因为这种论证的简单版本是谎言。Haskell 等语言并不因为更奇特就安全。Hackage 可以托管恶意包;Cabal 会很乐意运行一个被破坏的 `Setup\.hs`,而 Template Haskell 在编译时执行任意 IO,这如果说有什么不同的话,那是一个比安装后脚本更诱人的钩子。生态系统没有出现 Shai-Hulud 的主要原因在于没有人费心去构建一个,“没有人瞄准我们”就是通过隐晦实现的安全。如果注意力转移,事件也会随之而来。 有一些文化上的差异:社区更偏好更少但更大的库,因此传递闭包更小,在你的信任边界内独立的维护者账户也更少;规范更慢、更固定,缩小了被投毒版本可以潜入构建的时间窗口;包主要分发源代码,而不是预构建的二进制文件,因此没有不透明的 blob 需要审计。这些都有帮助。但没有一个是保证。 还有一个通常与 AI 论点相伴的第二条宣传:TypeScript 有更大的生态系统。你遇到的每一个问题都有一个经过实战考验的包,每一个框架都有一流的类型支持,工具打磨得闪闪发光。选择 npm,已经有人解决了它。 请注意,这个论点与紧挨着的另一个论点相互矛盾。我们默认选择 AI 最喜欢的语言的整个原因在于 AI 让我们能更快地编写更多代码。通过提示就能将一个实现从一周的工作变成一个下午的工作。但如果这是真的,那么庞大的包生态系统的边际价值就在实时崩溃。生态系统给你带来的好处是不需要自己编写代码。模型给你带来的好处是……不需要自己编写代码。无论哪种方式,结果是相同的。你越相信 AI 的生产力故事,生态系统的故事价值就越低,因为你可以用评估三个 npm 候选包的时间,凭空变出一个专注于特定功能的、无依赖的日期解析或状态机库版本。 而你生成的版本在安全性轴上相对容易获胜:它是你能阅读的代码,只做你需要的事,没有陌生人包的传递闭包拖在后面。你不引入的每一个依赖都是你不继承的攻击面和一个你不必信任的 `\.d\.ts`。因此,生态优势和生产效率优势在部分是同一个优势被计算了两次。而在 TypeScript 的情况下,被重复计算的那一半,正是拖着 npm 爆炸半径一起走的那一半。 ## 一个更新、更神话的人月 五十年前,Fred Brooks 给了我们经典的软件管理谬误:向一个延迟的项目增加人手只会让它更延迟。原因不是人没用。而是软件的限制因素从来不是原始劳动力。而是各部分和人之间沟通的成本,呈组合级增长,以及某些工作不可化约的串行性。你不能让九个女人一个月生出一个婴儿。 AI 辅助看起来像是在废除这一点。劳动力突然变得便宜且即时;边际贡献者是免费的。所以生成更多、更快。但 Brooks 的瓶颈从来不是生成代码的成本。而是让各片段协调一致的成本(集成、协调、验证),当你添加一个不知疲倦的生成器时,这个成本不会下降。它反而会上升。你并没有添加一个你可以与之沟通的同事,不管 Claude 告诉你多少次“您完全正确”;你添加了一个你必须事后与你的人类同事(即由他们阅读每一行代码并对照它接触的一切进行检查)沟通的水管。这种检查正是 Brooks 告诉我们的我们无法通过增加吞吐量来逃脱的串行、不可并行的工作。 这是以更高级且更危险的形式出现的神话人月,因为旧版本至少增加了携带着上下文和判断力的贡献者。新版本增加了不携带任何这些东西的产量,并将所有集成成本记在后续的人类头上。而恰好有一个工具可以在不增加通信图的人类链接的情况下扩展集成检查:一个健全的编译器。一个使不连贯组合不可表示的类型系统吸收了一整类“这些部分是否合适”的问题,交由机器在几秒钟内回答。这是唯一摆上台面且实际上吸收了一些 Brooks 定律所产生网络成本的东西。因此,采用水管并同时选择不健全的语言,是这一谬误最纯粹的现代形式:你扩展了工作的生产能力,却故意削弱了唯一能扩展工作集成能力的机制。你雇了九个女人,却扔掉了日历。 ## 结束语 让我们重新审视为你的 LLM 使用 TypeScript 的前提:“但模型在 TypeScript 上要好得多。”这在两个不同方向上都是错误的。 首先,即使承认这一前提,这也是讨论中最暂时的事实。模型能

相似文章

关于人工智能

Lobsters Hottest

作者回顾了自己从在老旧Macintosh上手动输入代码到使用Copilot和Claude等AI辅助代码补全工具的历程,并得出结论:尽管AI行业存在问题,但技术本身是有用的。

关于AI编程及其不满

Lobsters Hottest

卡尔·纽波特反思了人们对Claude Code等AI编程工具的最初热忱,以及开发者因隐藏漏洞、质量问题和不持续的工作流而日益幻灭,认为目前将所有代码生产外包给AI并不可行。