> 关键工具:Claude Code(终端自主 Agent)
> 技术栈阶:高阶——库级批量重构
> 完整演示:构思 → 创建项目 → 提示词编写 → AI 制作 → 项目检验 → 落地
> 预计耗时:300+ 文件项目,分十几批迁移,约 1~2 天(含审阅)
这一篇怎么读
"落地"在这里指把迁移成果安全合并进主干、CI 全绿。本篇演示如何让 Claude Code 批量重构,同时用工程纪律盯死它不偷工减料、不改坏行为。
阶段一 · 构思:先定义"什么算真正改好了"
- 场景:接手一个 300+ 文件、跑了五年的 JavaScript 项目,没类型、改一处怕崩一片。
- 目标:迁到 TypeScript(strict 模式),提升可维护性。
- 最大风险(构思阶段就要警惕):不是"改不动",而是"改得看起来对、实则偷工减料"——满屏
any、跳过难啃的依赖、悄悄改坏行为。 - 成功标准:strict 编译通过、原测试全绿、
any都有正当理由、没有任何运行时行为被改动。
阶段二 · 创建项目:拉代码、装 Agent、配过渡环境
- 拉代码并建分支(绝不在主干上直接动):
git clone <legacy-repo> && cd legacy-repo
git checkout -b migrate-to-ts # 专门的迁移分支
npm install && npm test # 先确认现有测试能跑、记下基线
- 启动 Claude Code:
claude
- 让它配可共存的过渡 tsconfig(关键:允许 .js 与 .ts 共存,才能逐文件迁移、全程可运行):
// tsconfig.json(关键片段)
{ "compilerOptions": {
"strict": true, // 严格模式:迁移的目的
"allowJs": true, // 允许 js/ts 共存,渐进迁移
"checkJs": false,
"noEmit": true
} }
为什么先建迁移分支 + 过渡配置
分支保证主干始终可用、出问题能弃掉重来;allowJs 让项目在迁移途中任何时刻都能编译能跑,从而每一批都可验证。这是大重构能"小步快跑"的前提。
阶段三 · 具体提示词编写:把纪律写进工单
提示词核心是设定质量标准 + 强制分批 + 每批可验证。绝不能说"把整个项目改成 TS"然后等它跑完。
起手提示词(在项目根目录启动 claude)
把这个 JS 项目渐进式迁移到 TypeScript。严格遵守纪律,分批进行。
【前置】tsconfig 已开 strict + allowJs,全程保持可编译可运行;
每批都要保证现有测试仍通过。
【迁移纪律——最重要】
- 每批只迁 5~10 个文件,从依赖最少的底层工具函数开始,自底向上。
- 【禁止滥用 any】推导不出就用 unknown + TODO 注释,集中列给我,
不要静默写 any 吞掉。
- 只做类型迁移,不要改任何运行时行为/逻辑。
- 每批后跑 类型检查 + 测试,都过了再下一批,并报告改了哪些文件、难点在哪。
先给我画依赖层级,并列出第一批(最底层 utils)的文件清单待我确认。阶段四 · AI 制作:看产出与第一处偷懒
Agent 先画依赖层级、列第一批 utils 清单(确认后开工)。第一批迁完,报告里出现了要盯死的偷懒——一个函数签名是 function parse(input: any): any:
// AI 初版(偷懒)
function parse(input: any): any { ... }
// 人介入后,要求据调用点反推真实类型
function parse(input: string): ParsedResult { ... }
这正是要揪的——any 让类型保护形同虚设。
阶段五 · 项目检验(上):盯死三类质量陷阱
5.1 顺序:自底向上,不是从入口
AI 一开始想从 main.js 入口改,错。入口依赖一切,类型会层层缺失。纠正为按依赖拓扑自底向上——每迁一层,上层引用时已有类型可用。
5.2 消灭 any
消灭 any 提示词
parse(input:any):any 不行。据所有调用点反推真实类型给出精确签名;
确实多类型就用联合类型或泛型,不要 any。
把项目里所有 any 列清单,逐个标注"真无法确定"还是"偷懒了"。指标陷阱
"能编译通过"会骗人——满屏 any 也能过,但类型保护失效。质量真标准是"any 有多少、是否都有正当理由",只能由人定和盯。
5.3 打破依赖死锁
迁到中层撞上一个没类型定义的老库,引发一连串编译错误,AI 反复打转。让它停下、由人决策:
打破死锁提示词
停止在这个库上反复试。给我三个选项的利弊:
(a) 给它写最小 .d.ts,只声明我们用到的 API;
(b) 升级到自带类型的新版(评估 breaking change);
(c) 换成有类型的等价库。
先别动手,列工作量和风险,我来定。最终选 (a),工作量最小、风险可控。"何时该停止让 AI 硬试、转由人决策",是高阶重构的关键判断力。
5.4 守住"不改行为"
AI 几次"顺手"把 == 改成 ===。看似改进,实则危险——遗留代码里那个 == 可能是有意的。严格制止:
行为冻结提示词
你迁移时改了运行时逻辑(== 改 ===),请回退所有这类改动。
本次只动类型,不动行为。你觉得"该顺手修"的逻辑问题,单独列
"重构后待办"清单,绝不夹带在类型迁移里。阶段五 · 项目检验(下):验收清单
| 检验项 | 操作 | 期望 |
|---|---|---|
| 行为不变 | 迁移前后跑完整测试套件对比 | 结果完全一致 |
| any 审计 | 全局搜 any | 每个都有正当理由,无偷懒 any |
| strict 真开 | 查是否有大面积 @ts-ignore 压制 | 没有靠注释蒙混 |
| 可回滚 | 每批是独立 commit | 任一批出问题能单独回退 |
阶段六 · 落地:安全合并进主干、CI 守门
迁移成果要"落地"为主干代码,且让 CI 把住以后不再倒退。
- 每批一个 commit、最后整理成 PR:迁移分支推上去开 PR,diff 清晰、可逐批 review。
- 在 CI 加类型检查关卡,防止以后有人再塞回无类型代码:
# .github/workflows/ci.yml(关键片段)
- run: npx tsc --noEmit # 类型不过就挡住合并
- run: npm test
- 关掉 allowJs,完成最后收口:当所有文件都迁完,把
allowJs关掉、tsconfig收紧,确保新代码必须是 TS。 - 合并:CI 全绿 + 人审通过后合并主干。迁移正式落地。
落地的真正意义
重构落地不只是"改完了",而是用 CI 把质量固化下来——让 tsc --noEmit 成为合并的硬门槛,这次迁移的成果才不会随时间被侵蚀。
30% 复盘:人类到底守住了什么
AI 能飞快批量改文件、推导大部分类型(70%)。让这次重构"真提升质量而非制造假象"的 30%,全是人类的质量纪律:
| 30% 工程点 | 人类做了什么 | 不做会怎样 |
|---|---|---|
| 迁移顺序 | 自底向上按依赖拓扑 | 从入口开始,类型层层缺失、返工 |
| 消灭 any | 盯死每个 any,要求精确类型 | "能编译"的假 TS,保护失效 |
| 打破死锁 | 该停就停,由人决策 | AI 在不兼容依赖上无限打转 |
| 行为冻结 | 严禁夹带逻辑改动 | 隐性引入新 bug,难定位 |
核心教训:当 AI 能批量改代码,人的价值就上移到"定义什么算真正改好了、并盯着它不许走捷径"。 重构最值钱的不是快,而是干净——"干净"的标准,只有人能定能守。
可复用心法与提示词模板
带得走的三条
- 大重构必须分批 + 每批可验证:小步快跑,每批跑通测试再继续。
- 盯死偷懒指标:
any、@ts-ignore这类"能过但没意义"的捷径要人审计。 - 一次只做一件事:类型迁移就只动类型,逻辑优化单独排期。
通用"大规模重构"提示词骨架:
把项目从 <A> 渐进式迁移到 <B>。遵守纪律:
1. 先配可共存的过渡配置,保证全程可编译可运行。
2. 分小批(每批5~10文件),按依赖自底向上;每批先给我清单确认。
3. 禁止偷懒捷径(any/@ts-ignore),无法确定的集中列清单,不静默吞掉。
4. 只做本次目标改动,不夹带其他"顺手优化",另列待办。
5. 每批跑类型检查+测试,全绿才继续,并报告改了什么、难点在哪。
6. 遇反复失败的死锁就停,给我选项利弊,由我决策。