为了让 AI 写代码更稳,我们真要忍受更难学的库吗
团队推进 AI 编程时,最棘手的通常不是 AI 写不出代码,而是它写出的代码看起来没什么问题,真正运行后却处处是坑。这也带来了一个有些反常的问题:有些库对人类开发者来说学习曲线极其陡峭,AI 却非常擅长调用。如果一个库能让 Claude Code 或 Kiro 更可靠地完成调用,即使它会让开发者更痛苦,项目选型时是否也应该优先考虑它?
Effect 正是这一逻辑最明显的例子。它号称是 AI 时代的可靠 TypeScript 方案。传统异步函数通常拥有明确的成功类型,失败行为却可能只写在注释里,或者需要开发者依赖经验,也就是 Tribal Knowledge 去猜。Effect 则把错误直接放进了类型通道。
比如,一个项目定义了多种错误类型:
import { Data, Effect } from 'effect'
export class NotFoundError extends Data.TaggedError('NotFoundError') {}
export class RateLimitError extends Data.TaggedError('RateLimitError') {}
export class NetworkError extends Data.TaggedError('NetworkError') {}
接下来编写加载用户信息的函数时,Effect 会强制开发者处理这些错误:
export const loadProfile = (scenario: Scenario) =>
Effect.gen(function* () {
if (scenario === 'not-found') {
return yield* new NotFoundError({ handle: 'agent-editor' })
}
if (scenario === 'rate-limited') {
return yield* new RateLimitError({ retryAfterSeconds: 30 })
}
if (scenario === 'offline') {
return yield* new NetworkError({ reason: 'The demo API is offline.' })
}
return profile
})
类型检查如何自动捕获 AI 遗漏的分支
这里最关键的地方在于,假设 AI 在后端逻辑中偷偷加入了 MaintenanceError,却没有同步修改前端,assertNever 这样的类型检查便会在编译阶段直接找出这个漏洞。
这个闭环让 AI 的输出变得极其确定,但相应的代价是:如果团队成员不熟悉函数式编程,看到这类代码可能会感到完全无法理解。
样式管理如何避免 AI 混淆全局选择器
样式管理中也有类似情况,比如 StyleX。传统的 CSS 全局选择器很容易让 AI 混淆,常见的问题就是修改了 A 页面,结果 B 页面的样式也跟着出问题。StyleX 将样式定义在一个具备强类型的 JS API 后面:
const styles = stylex.create({
result: {
borderRadius: '8px',
padding: '16px',
},
})
有了类型约束,AI 编写样式时不再靠猜测类名,而是像调用接口一样调用样式。大部分低级错误都会在编译阶段被拦截,不必等页面真正渲染后才发现问题。
AI 效率提升是否带来了认知壁垒
但在公司内部推行这类方案时,我发现了另一个矛盾:AI 的确提升了开发效率,同时也在技术栈周围筑起了一道“认知墙”。目前,AI 对这套技术栈的理解程度可能已经超过负责维护它的开发者。如果某天 AI 不在身边,或者生成的代码中出现了一个极其隐蔽的逻辑 Bug,人类维护者或许需要花费三倍的时间,才能读懂这段代码的作用。
未来的趋势可能是,团队会为了“AI 可维护性”牺牲一部分“人类可读性”。如果一个库能为 AI 提供更加精准的信号,例如强类型错误通道和确定的 API 边界,那么即使开发者需要花一个月阅读文档,面对公司的规模化交付,这种交换依然划算。相比让用户从生产环境中反馈 Bug,能够在编译阶段就被拦截的错误,成本要低得多。
全部回复 (4)
想当场把话说完?进全球 AI 聊天室,登录就能开口。
用了 Zod 之后,AI 生成的接口代码不仅编译无误,甚至能在类型层面直接暴露出遗漏的错误分支——比如你定义了 NotFoundError、RateLimitError 等,但 AI 在修改后端逻辑时偷偷加入了 MaintenanceError,Zod 的 assertNever 就会在编译阶段直接报警,强迫你补全所有可能的错误处理路径。这样,AI 的输出就不再是“看起来没问题”的伪完整,而是被硬性绑定在了你明确声明的类型约束上,让错误在代码阶段就被“驯服”而不是等到运行时暴露。虽然 Zod 的学习曲线比传统库陡峭,但它确实让 AI 编程的“可靠性”从“看起来没问题”升级到了“编译时就能确认”。
约束强了,AI 写的逻辑才不离谱。可以把各种错误纳入类型通道,并让 UI 分支用 assertNever 做穷尽检查;AI 新增 MaintenanceError 却漏改前端时,TypeScript 会在编译阶段报错,不必等运行后才像开盲盒。
效率确实是 AI 编程库的核心优势,但真正能让开发者少走弯路的,往往是那些在 编译阶段 就能捕获逻辑错误的设计。比如 Effect 通过强制性错误类型化,就让 AI 代码在写完后立即暴露出所有遗漏分支——比如你在
loadProfile中忘记处理MaintenanceError,assertNever会在编译时拒绝通过,而不仅仅是等到运行时发现崩溃。这让 AI 输出的代码不再是“看起来没问题”,而是“经过 TypeScript 的严格审查”,从而避免了“AI 修改程序 → 运行发现问题 → 重新修改”这种反复循环。相比之下,传统异步函数的错误处理往往只能依赖注释或经验(Tribal Knowledge),而 Effect 则把错误“直接放进了类型通道”,让 AI 无需猜测,只需“调用”已定义的错误类型即可。这意味着,即使 AI 编写的代码看起来“逻辑清晰”,但如果它在隐式分支(如未列举的
scenario)或类型不匹配上犯错,TypeScript 会在编译时提示,而不仅仅是等到用户手动调试。这种“闭环”机制让 AI 输出的代码不再依赖开发者的“经验”,而是完全由类型系统保证可靠性——尽管前提是开发者需要学习函数式编程的基础。我宁愿花时间啃那个难搞的库,把 Effect 的
Data.TaggedError写进代码里,让 AI 写出的每一行都被类型检查逼着处理完再敢跑。