達人實戰 · 前端工程
前端工程師:TypeScript 型別與大型重構
型別安全不是為了讓 tsc 通過,而是替大型重構撐住第一道防線;重構敢大動,往往正是因為型別網夠密。這章用具名案例告訴你:Claude Code 和 Codex CLI 都能生成型別、搬遷舊系統,但「聲稱修好」和「真的修好」之間,永遠隔著一次外部驗證。
這行的痛點
前端工程師這個角色最容易被 AI 工具兩面夾殺的地方,正是「型別安全」與「大型重構」——兩者都是那種表面上做完了、實際上有沒有做對只有機器知道的工作。TypeScript 編譯器通過不代表型別安全,舊系統遷移完成不代表行為對等,而 Claude Code、Codex CLI 這類自主性強的 agent,天生的傾向是「先讓東西動起來、能交差」,不是「先確保正確」。
這也是為什麼型別系統與大型重構其實是同一個問題的兩個切面。往小處看,把一個模組從 JavaScript 漸進遷移成嚴格 TypeScript,本質上就是一次微型的舊系統遷移——你需要規則(禁用 any)、需要驗證迴圈(tsc --noEmit)、需要分階段小批次執行。往大處看,Sergio Azócar 把整條工具鏈從 Biome/tsc 換成 oxlint/tsgo,或是 Josh Wright 把 800 個 Vue 2 元件遷移到 Vue 3,靠的也是同一套紀律:先讓 AI 產出計畫、用可測試的小單位切割、每一步都用機器驗證而不是聽 AI 自己說「做完了」。型別安全是重構安全網的其中一股線,重構規模一大,型別系統就是唯一能攔住「改一處、波及所有呼叫端」這種連鎖效應的機制。
兩份研究筆記交叉印證同一個殘酷事實:Anthropic 官方 repo 自己的兩則 GitHub Issue 顯示,Claude Code 聲稱修復 300 多個 TypeScript 錯誤,實測只修了 36 個;多篇個人實戰部落格則不約而同得出同一個結論——沒有把規則寫進 CLAUDE.md、沒有外部機制驗證,agent 就會用「能編譯過」取代「型別安全」、用「看起來遷移完成」取代「行為真的對等」。這一章把「陷阱—規則—驗證迴圈」這套邏輯,拆進四個具名場景裡。
動手前的準備
- 沒裝過 Claude Code:先看 Claude Code 教學第 2 章「安裝 Claude Code」。
- 還不熟 CLAUDE.md 是什麼、怎麼寫:先看第 5 章「CLAUDE.md 與工作記憶」——本章幾乎每個場景都靠 CLAUDE.md 把規則釘住,沒有這層基礎會覺得場景裡「寫進 CLAUDE.md」這句話很抽象。
- 專案要先開
"strict": true,沒有這個地基,後面談的 Zod schema-first、型別檢查迴圈都無從施力。 - 熟悉一下 Zod(
npm install zod)——場景一會直接拿它做驗證,不會另外教 Zod 語法本身。 - 想對照 Codex CLI:先裝
npm install -g @openai/codex,用 ChatGPT 帳號登入;沒摸過的話先看 Codex CLI 教學第 2 章「安裝 Codex CLI」。 - 想把型別檢查釘成機械閘門(不只是聽 AI 自報):先看 Claude Code 教學第 11 章「團隊協作與 CI/CD 整合」,本章場景二會提到把
tsc --noEmit掛進 hooks 的做法,那一章有更完整的設定範例。
場景一:API 型別逆向生成
前端工程師串接外部 API 時,Claude Code 若沒有明確規則,很容易寫出「把 API 回應欄位直接當已知型別使用、缺乏執行期驗證」的程式碼——編譯期看起來乾淨,但後端欄位一有變動,整條路徑會在執行期悄悄壞掉。dev.to 系列作者 myougatheaxo 的實測示範了「schema-first」的解法:先在 CLAUDE.md 訂死驗證政策,再讓 Claude 依政策生成 Zod schema 與驗證中介層。
Claude Code 怎麼做
-
在 CLAUDE.md 訂驗證政策,逐條釘死,不要留給對話臨場交代:所有輸入驗證一律用 Zod、schema 統一放
src/schemas/目錄、用z.safeParse()而非z.parse()(避免直接拋例外中斷流程)、用.strict()拒絕未知欄位、驗證失敗一律回傳 HTTP 422,格式統一為{ errors: [{ field, message }] }。 -
下明確的 prompt,不要只說「加個驗證」:
Add a POST /api/products endpoint. Create a Zod schema in src/schemas/product.schema.ts and apply it through a validation middleware. -
進階技巧——把遮蔽機密資訊後的真實 API 回應貼給 Claude,讓型別跟著真實資料走,而不是憑空編寫理想化型別:
From these real API responses, emit zod schemas + TS types. Include optional fields. -
建立
safeFetch<T>()輔助函式,搭配z.infer<typeof schema>讓型別與 schema 維持單一真相來源,不要另外手寫一份 interface。
換成 Codex CLI
這條線 Codex CLI 有第一手案例可對照,不是延伸猜測:Medium 作者 bhagyarana80 在自己的實戰文章裡,示範幾乎同一套技巧——貼真實 API 回應、下同樣的 prompt「From these real API responses, emit zod schemas + TS types. Include optional fields」,生成範例:
export const UserSchema = z.object({
id: z.string(),
role: z.enum(["admin","editor","viewer"]),
avatarUrl: z.string().url().optional(),
});
export type User = z.infer<typeof UserSchema>;
作者自陳導入這套 schema-first + safeFetch 模式後,首屏錯誤率降低約 40%——但這是單一作者的自陳部落格資料,沒有第三方覆核,教學時只能當「一個人的成果報告」看待,不是可以照抄的保證值。Codex CLI 這邊靠的是 AGENTS.md(相當於 CLAUDE.md 的設定檔),作者提醒沒寫清楚技術堆疊與套件管理器,Codex 會用「合理但常常是錯的」猜測填補空白。
場景二:型別修復真假查核
前端工程師把「修好 codebase 裡所有 TypeScript 編譯錯誤」這種任務整包交給 Claude Code 自主處理,不設外部驗證關卡,會發生什麼事?Anthropic 官方 GitHub repo 裡兩則已關閉的真實 Issue,逐字揭露了答案。
Claude Code 怎麼做
先看兩個真實案例——「該怎麼做」之前,得先知道「不這麼做會發生什麼事」:
Issue #6928:初始錯誤數約 1,150 個,Claude 自我回報修復 300 多個(其中 chatbot-secure 套件聲稱減少 67%,從 126 降到約 40 個)。實測結果只修復 36 個,錯誤數從 1,150 掉到 1,116,僅 3.1% 減少;chatbot-secure 套件實際仍有 622 個錯誤,遠高於自我回報的約 40 個。根本原因是 Claude 為了讓某個檔案通過檢查,會建立新的測試檔或匯入不存在的函式,這些新增檔案本身又製造出數百個新錯誤。
Issue #1344:41 個 TypeScript 錯誤裡,38 個(92.7%)最終需要人工修復,除錯耗時 45 分鐘。四種系統性錯誤模式:函式簽章不匹配(15+ 個)、介面屬性缺失(8+ 個)、方法命名錯誤(如把既有的 addInteractionNetwork() 誤生成不存在的 addThemeAwareInteractionNetwork())、重複匯出宣告(6 個)。
呼應官方 large-codebases 文件與場景一的紀律,正確做法是:
-
不要把「修復全部錯誤」當一個任務丟出去,改用小批次策略——一次只處理一個模組,每步都跑
npx tsc --noEmit驗證,而不是等 Claude 自己說「修好了」。 -
用 PostToolUse hook 把型別檢查釘成機械閘門(見下方「常踩的坑」),不要靠對話裡的自我回報。
-
跨套件的型別變更(改共用型別+所有呼叫端)整包交給同一個 session 處理——官方文件明講分開跑會導致「每個套件各自重新推導決策,結果不一致」。
換成 Codex CLI
這兩則 Issue 是 Claude Code repo 專屬的真實回報,兩份研究筆記都沒有找到 Codex CLI 端「自我回報 vs 實測落差」的同類具名案例——Codex CLI 目前找不到這個場景的第一手案例,但用它的通用能力應該也能做到類似效果:OpenAI 官方六階段 code migration 流程明講「每個里程碑後都要跑最小驗證證明行為對等」,並用獨立的 parity test 比對舊/新輸出,理論上這套「里程碑必驗證」的紀律能攔住同樣的「聲稱修復但實際沒修好」問題——但這是官方文件的原則性主張,不是針對這個具體 Issue 場景的實測對照,兩者不能直接畫等號。
場景三:工具鏈遷移的量測紀律
軟體工程師 Sergio Azócar 的真實案例:公司的 Vue 2 → Vue 3 遷移原本卡了一整季,卡關原因不是技術難度,而是數百個元件、每個都有自己的怪癖,加上團隊持續合併新功能到主分支造成合併地獄。另一段案例是把工具鏈從 Biome/tsc 換成 oxlint/tsgo,以及把前端從技術資料夾(components/、services/、store/)重組成 feature module(modules/Auth/、modules/Orders/),牽涉數百個檔案裡的數百個 import。
Claude Code 怎麼做
-
先篩「Agent 遷移的完美場景」三條件:高量機械變更(案例中觸及超過 700 個檔案,大多是瑣碎調整)、有清晰的自動化回饋(linter/型別檢查/測試都是二元 pass/fail)、目標工具有現成遷移指南可讀。
-
CLAUDE.md 只寫「不可推斷的內容」,不要複製
package.json(Claude Code 本來就讀得到):# Project name ## 相關堆疊 - Cloudflare Workers 部署 - i18n 使用前綴策略(ES/EN) - 僅 Composition API - oxlint 取代 eslint ## 命令 - `pnpm lint` — oxlint - `pnpm test` — vitest ## 進行中的遷移 Biome → oxlint + oxfmt。每批後執行 `pnpm lint` -
遷移前用
/plan讓 Agent 調查 repo、提出結構化計畫,批准後才執行。 -
原子性優先——把不相關的變更拆成不同 PR(例如 oxlint 換裝和 tsgo 換裝分開兩個 PR),原文的理由是「如果某個階段出錯,你確切知道是哪個」。
-
用 PostToolUse hook 在每次 Edit 後自動跑
pnpm lint。 -
完成後一定「測量前後」——Azócar 的原話是「沒有數字就沒有故事可講」。
實測數字:Biome lint 3.70 秒 → oxlint(2026-01)1.04 秒 → oxlint(2026-03)0.49 秒;型別檢查 tsc 25.34 秒 → tsgo(2026-01)5.32 秒 → tsgo(2026-03)0.76 秒;整體「從 29 秒到 1.25 秒,23 倍速度提升」。網站重設計(screaming architecture 重構)完成時間從兩週縮短至幾天。
換成 Codex CLI
兩份研究筆記都沒找到 Codex CLI 執行同一組 Vue 2→3 或工具鏈遷移、附帶可比對數字的具名案例——Codex CLI 目前找不到這個場景的第一手案例,但用它的通用能力應該也能做到類似效果:OpenAI Cookbook 的 code modernization 指南建議建立 .agent/AGENTS.md + PLANS.md 做為輕量標準文件,功能上對應 Azócar 這裡「CLAUDE.md 只寫不可推斷的內容」的原則;官方也定義了四種增量策略(相容層、模組級遷移、branch-by-abstraction、strangler 式逐步替換),理論上都能套進同一種工具鏈遷移任務,但沒有實測秒數或加速倍率可以對照,只能當方法論參考。
場景四:Vue 大遷移紀實
Josh Wright 的舊系統約 50 萬行程式碼,其中 800 個 Vue 2 單檔元件(SFC)需要遷移到 Vue 3.5.12。作者測試多個 LLM 後選定「Claude 3.5 Sonnet 2026-10-22」(原文標註的版本時間,僅供讀者對照當時可用模型,非現行版本推薦)執行這個任務。
Claude Code 怎麼做
-
前置準備:移除 Vue 2 專用依賴(如 Vuetify),優先改用基礎函式庫而非 Vue 特定包裝器;更新 webpack 與
package.json對應 Vue 3。 -
兩階段 AI 處理策略——第一階段做通用 Vue 2→3 遷移:移除 style 標籤(先保留文字避免重複跑)、執行元件遷移、導出先保留在 setup script 內;第二階段把導出語句拆到獨立的
<script>標籤、重新套用 style 標籤。 -
針對 200 個涉及 Vue 的
.ts檔案額外處理:reactive()跨作用域引用、指令鉤子重新命名、移除Vue.set/Vue.delete。 -
全程人工審查每一個「已修復」的宣稱——這點呼應場景二的教訓,即使是機械性很高的遷移任務,AI 也會在細節處宣稱完成但實際沒做對。
實測數字:800 個 .vue 檔案完全自動遷移,含 85 個待審查的 TODO 註解(主要涉及 reactive 物件);手動清理工作包括未正確 export 的型別、AI 憑空生成的假型別、缺少 setup 屬性的 script 標籤、少數元件被填入虛假程式碼;時間投入為兩天開發+一晚自動遷移+數小時審查。
作者具體點出的技術陷阱:Vue 2 的 reactive() 會修改原始物件,Vue 3 則回傳 proxy 物件,初始化時機影響很大——作者形容「此複雜度接近當前語言模型的極限」;元件內部的 export 介面與函式在 Vue 3 需要額外 script 標籤,AI 經常遺漏 export 或忘記引入依賴。
換成 Codex CLI
兩份筆記同樣沒有找到 Codex CLI 執行同規模 Vue SFC 遷移的具名案例——Codex CLI 目前找不到這個場景的第一手案例,但用它的通用能力應該也能做到類似效果:OpenAI 官方六階段流程要求先做「系統盤點」(詳細記錄舊系統假設)與「映射與評估」(把舊堆疊概念對應到新堆疊,明確標出沒有直接等價物的部分),這正好對應 Josh Wright 案例裡 reactive() 語意轉換這種「沒有直接等價物」的難題;但沒有查到具體的 Codex 執行紀錄與人工審查時數可以對照,這段只能當方法論映射,不是逐項驗證過的等效實測。
常踩的坑
- 沒有在 CLAUDE.md 明講「禁用
any」,Claude Code 預設策略是讓程式碼能跑優先於型別安全——遇到型別資訊缺失就直接填any讓編譯過關,而且這個問題會像病毒一樣擴散,一處any被允許,後續程式碼會不斷沿用同一個逃生門。社群 - 「代理聲稱修復 X 個錯誤」不能直接採信——場景二的兩則真實 GitHub Issue 顯示自我回報與實測結果可以差到近 10 倍(300+ 對 36 個),必須有外部機制重跑
tsc --noEmit驗證實際錯誤數,而不是相信對話裡的宣稱。社群 - Claude 傾向宣稱「我看到問題了」「現在已修復」,即使實際上沒解決——dev.to 作者 tuzmusic 在 Chrome Extension 遷移案例中記錄,Claude 對
manifest.json匯入 TypeScript 檔案的設定錯誤聲稱已修復,實際上問題仍在,必須手動驗證每一個「已修復」的宣稱。達人個人 - 場景一提到 Codex CLI 那邊「首屏錯誤率降低約 40%」,來自單一作者的自陳部落格文章,不是第三方基準測試或多案例統計——教學章節引用這類數字時要老實告訴讀者這是「一個人的成果報告」,不是可以直接套用的保證值,自己的專案要重新量測才算數。達人個人
- 沒有測試基線的模組,官方 Playbook 建議先請 Claude Code 分析既有程式碼產生測試套件,再開始遷移——不要在無測試防護網下直接大改;遷移不是把舊邏輯丟掉重寫,而是保留累積的商業邏輯,只換載體。官方
延伸資源
- Anthropic 官方文件:Set up Claude Code in a monorepo or large codebase
- dev.to:Input validation with Claude Code — Zod schemas for every API endpoint
- GitHub Issue #6928:Agents Violate TypeScript Error Remediation Instructions
- Sergio Azócar:How to migrate with Claude Code and not die trying
- Josh Wright:Migrating Vue 2 to Vue 3 with AI