> 关键工具:Claude Code(终端自主 Agent)

> 技术栈阶:高阶——库级批量重构

> 完整演示:构思 → 创建项目 → 提示词编写 → AI 制作 → 项目检验 → 落地

> 预计耗时:300+ 文件项目,分十几批迁移,约 1~2 天(含审阅)

这一篇怎么读

"落地"在这里指把迁移成果安全合并进主干、CI 全绿。本篇演示如何让 Claude Code 批量重构,同时用工程纪律盯死它不偷工减料、不改坏行为。

阶段一 · 构思:先定义"什么算真正改好了"

  • 场景:接手一个 300+ 文件、跑了五年的 JavaScript 项目,没类型、改一处怕崩一片。
  • 目标:迁到 TypeScript(strict 模式),提升可维护性。
  • 最大风险(构思阶段就要警惕):不是"改不动",而是"改得看起来对、实则偷工减料"——满屏 any、跳过难啃的依赖、悄悄改坏行为。
  • 成功标准:strict 编译通过、原测试全绿、any 都有正当理由、没有任何运行时行为被改动

阶段二 · 创建项目:拉代码、装 Agent、配过渡环境

  1. 拉代码并建分支(绝不在主干上直接动):
git clone <legacy-repo> && cd legacy-repo
git checkout -b migrate-to-ts        # 专门的迁移分支
npm install && npm test              # 先确认现有测试能跑、记下基线
  1. 启动 Claude Code
claude
  1. 让它配可共存的过渡 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 把住以后不再倒退。

  1. 每批一个 commit、最后整理成 PR:迁移分支推上去开 PR,diff 清晰、可逐批 review。
  2. 在 CI 加类型检查关卡,防止以后有人再塞回无类型代码:
# .github/workflows/ci.yml(关键片段)
- run: npx tsc --noEmit      # 类型不过就挡住合并
- run: npm test
  1. 关掉 allowJs,完成最后收口:当所有文件都迁完,把 allowJs 关掉、tsconfig 收紧,确保新代码必须是 TS。
  2. 合并:CI 全绿 + 人审通过后合并主干。迁移正式落地。

落地的真正意义

重构落地不只是"改完了",而是用 CI 把质量固化下来——让 tsc --noEmit 成为合并的硬门槛,这次迁移的成果才不会随时间被侵蚀。

30% 复盘:人类到底守住了什么

AI 能飞快批量改文件、推导大部分类型(70%)。让这次重构"真提升质量而非制造假象"的 30%,全是人类的质量纪律:

30% 工程点人类做了什么不做会怎样
迁移顺序自底向上按依赖拓扑从入口开始,类型层层缺失、返工
消灭 any盯死每个 any,要求精确类型"能编译"的假 TS,保护失效
打破死锁该停就停,由人决策AI 在不兼容依赖上无限打转
行为冻结严禁夹带逻辑改动隐性引入新 bug,难定位

核心教训:当 AI 能批量改代码,人的价值就上移到"定义什么算真正改好了、并盯着它不许走捷径"。 重构最值钱的不是快,而是干净——"干净"的标准,只有人能定能守。

可复用心法与提示词模板

带得走的三条

  1. 大重构必须分批 + 每批可验证:小步快跑,每批跑通测试再继续。
  2. 盯死偷懒指标any@ts-ignore 这类"能过但没意义"的捷径要人审计。
  3. 一次只做一件事:类型迁移就只动类型,逻辑优化单独排期。

通用"大规模重构"提示词骨架

把项目从 <A> 渐进式迁移到 <B>。遵守纪律:
1. 先配可共存的过渡配置,保证全程可编译可运行。
2. 分小批(每批5~10文件),按依赖自底向上;每批先给我清单确认。
3. 禁止偷懒捷径(any/@ts-ignore),无法确定的集中列清单,不静默吞掉。
4. 只做本次目标改动,不夹带其他"顺手优化",另列待办。
5. 每批跑类型检查+测试,全绿才继续,并报告改了什么、难点在哪。
6. 遇反复失败的死锁就停,给我选项利弊,由我决策。