RelayVano

← 全部明信片

上海小团队的周五改造:用 AI 把记账小应用逐步迁到 TypeScript

实地行程 ZH

周五要改的是记账应用,不是重写整个项目

假设你在上海的一支小团队维护一个记账网页:输入金额、选择分类,再查看本月合计。它用 JavaScript 和 Vite 开发,已经能正常工作。最近,同事把金额字符串直接参与相加,页面出现了错误结果。你想引入 TypeScript,又不想为此停掉新功能开发。

这正适合小步迁移。目标不是让 AI 一次改完所有文件,而是先让最容易出错的数据拥有明确类型,再逐步扩大检查范围。每一步都保留一个能运行、能撤回的版本。

TypeScript 给金额和账单加上明确约定

可以把 TypeScript 理解为带有类型检查的 JavaScript。你声明金额应该是数字后,检查器就能提醒你:这里传进来的可能是字符串。编辑器也能根据类型提供更准确的补全,帮助你找到函数的调用位置。

但类型检查不是数据消毒器。输入框的值仍然是字符串,服务器返回的数据也可能不符合约定。你依然需要转换金额、检查是否为有效数字,并处理异常。TypeScript 通常在构建时被转换成 JavaScript,浏览器不会替你执行这些类型约定。

先给 Vite 项目留下一条退路

开始前,提交当前代码,并记下添加账单、删除账单、刷新后恢复数据这三条操作的正常结果。如果项目已有测试,先跑一遍,确认原本没有失败项。

在这个 Vite 示例中,可以先运行 npm install -D typescript,再创建 tsconfig.json。请让 AI 根据现有目录和依赖建议配置,而不是复制别人的完整模板。重点确认以下选项:

  • allowJs 设为 true,让尚未迁移的 JavaScript 文件继续存在。
  • checkJs 暂时设为 false,避免第一天就检查全部旧文件。
  • strict 设为 true,让已迁移文件接受严格检查。
  • noEmit 设为 true,由 Vite 负责生成构建产物。
  • include 覆盖实际源码目录,模块解析设置与现有工具保持一致。

此后用 npx tsc --noEmit 单独检查类型。不要把开发服务器能够启动,当成类型检查已经通过;不少构建工具只转换语法,并不完整检查类型。

让 AI 先迁移一个金额计算文件

第一批选择不依赖页面的计算函数,例如汇总账单金额的 totals.js。把它改为 totals.ts,再为输入和返回值补充类型。含有 JSX 的组件应使用 .tsx,而不是 .ts。

给 AI 的任务越小,越容易审查。可以这样写:“请只迁移 totals.js 及必要的引用位置,保持现有计算行为。先列出你对账单数据的假设,再修改代码。不要引入新依赖,不要用 any 或忽略检查来掩盖错误,最后列出验证命令。”

如果 AI 不知道金额能否为空,就让它先问,不要猜。迁移时也别顺手调整舍入规则或重写存储逻辑,否则发现差异后,很难判断是类型改造还是业务变更造成的。

在输入框和本地存储处检查真实数据

下一步才处理页面与数据入口。输入框读到的金额需要显式转换,并检查是否有限、是否符合业务范围。从本地存储解析出的对象,也应先检查结构,再作为账单使用。

尤其留意 AI 添加的类型断言。把一个对象断言为账单,并不能证明它确实包含有效金额。遇到来源不确定的数据,可以先用 unknown 表示,再通过检查缩小类型范围;这比直接使用 any 更能保留检查价值。

每次提交都同时通过检查和实际操作

每迁移一小组文件,就运行类型检查、已有测试和生产构建,再手动重复那三条核心操作。检查失败时,把完整错误和相关文件交给 AI,并要求最小修复,而不是让它继续扩大改动范围。

审查差异时,特别关注被删除的判断、突然增加的默认值,以及没有解释的类型断言。类型检查通过不等于业务正确:合计是否准确、旧账单能否读取,仍要靠测试和实际操作确认。

把 AI 接入方式和迁移预算一起控制

如果你希望按用量使用 AI 辅助迁移,可以考虑 RelayVano,并注册账号后先用一个小文件评估效果。它支持 Claude Code、Codex、Gemini CLI 和兼容 OpenAI 的 SDK;API 基础地址为 https://api.relayvano.com,具体配置方式以所用工具为准。密钥应放在本地环境变量或安全配置中,不要提交到仓库,更不要写进浏览器代码。

这次周五改造的交付标准可以很朴素:金额计算已有明确类型,关键数据入口有检查,旧功能仍然可用。剩余 JavaScript 文件以后再迁移。对第一次接触 TypeScript 的人来说,一个可靠的小改动,比一份无法审查的大补丁更有价值。

同一条航线上的其他明信片