剛開始推廣 Vibe Coding 時,我常被質疑「工程不夠嚴謹」、「只能做 demo」。有次甚至有開發者直接對我說:「你說你在 vibe,我就不敢接你的 code。」那一刻我才意識到,Vibe Coding 在部分人眼中等同於「不可信任」。
說穿了,這些質疑其實反映了一種普遍的焦慮:AI 幫忙寫程式,會不會型別不明、缺乏測試、結構混亂,甚至無法維護?
不過,經過一段時間的實驗與實戰,我發現 Vibe Coding 並不等於混亂。只要建立對的工程基礎,例如 TypeScript 強型別、Zod 做資料驗證、JSDoc 提供結構化語意,以及 Vitest 保證測試品質,靈感式開發不只可以穩定落地,甚至在效率與品質上都能超越傳統流程。
如果你也在嘗試讓 ChatGPT 寫出來的程式碼更穩定、更可用,這篇文章會給你不少實用的方法和信心。我將分享如何把「只存在於 ChatGPT prompt 裡的想法」,透過 TypeScript、Zod、JSDoc 及 Vitest 工具,真正落實到產品級開發流程。我平時經常結合 ChatGPT 進行開發,這裡也會示範如何用工程化工具,讓 AI 生成的程式碼變得更可靠、可維護。
TypeScript:型別守門員,讓 vibe code 不再踩雷
在 Vibe Coding 的流程中,最令人擔憂的通常是資料型別的混亂、結構不一致與潛藏的 bug。ChatGPT 雖然能高速生成程式碼,但如果缺乏明確的型別約束,無論是資料流轉還是模組協作,都容易出現難以追蹤的錯誤。TypeScript 作為強型別語言,正好扮演了這個「守門員」的關鍵角色。
我的經驗:沒有型別約束的隱憂
舉個簡單例子:假設你要處理一個來自 API 的使用者資料,若無型別約束,ChatGPT 可能會寫出這樣的 JavaScript 程式碼:
function greetUser(user) {
return `Hello, ${user.name}!`;
}
但如果 user 物件缺少 name
屬性,就會出錯且很難追蹤。這在大型專案、多人協作或複雜資料流程中,潛藏的風險極高——你可能直到 production 才發現 bug,甚至還無法迅速定位錯誤來源。
TypeScript 一出手,結構安全又明確
使用 TypeScript,你可以這樣設計:
interface User {
name: string;
age: number;
}
function greetUser(user: User): string {
return `Hello, ${user.name}! 你今年 ${user.age} 歲。`;
}
// 型別安全的用法
greetUser({ name: 'Alice', age: 25 }); // OK
// 下面這行在編譯階段就會被 TypeScript 報錯
// greetUser({ name: 'Bob' });
這樣一來,無論是 AI 生成還是手寫,code 都會自動對齊你的資料結構規範,避免型別擦邊球。同時,型別提示、IDE 自動補全與靜態分析也能大幅提升開發效率,團隊協作時每個人都能清楚知道資料內容和預期格式。
泛型、型別推斷與延展性
TypeScript 不僅能描述靜態結構,還支援泛型(Generics)與 interface 擴展,讓你能彈性設計複雜資料流或多來源整合:
interface ApiResponse<T> {
data: T;
status: number;
error?: string;
}
const response: ApiResponse<User> = {
data: { name: 'Alice', age: 25 },
status: 200
};
// 泛型的威力:你可以快速定義任何資料結構的 API 回應
interface Post {
id: string;
title: string;
}
const postResponse: ApiResponse<Post> = {
data: { id: 'p001', title: 'TypeScript 超能力' },
status: 200
};
TypeScript 的型別推斷機制也讓你省去冗長註解,專注在設計資料結構:
const users = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 32 }
];
// TypeScript 會自動推斷 users 的型別
users.forEach((user) => {
console.log(user.name, user.age);
});
與現有 JavaScript 完美融合
TypeScript 能無縫轉譯為標準 JavaScript,支援各種瀏覽器與執行環境。你可以在現有 JS 專案中逐步引入 TypeScript,無痛升級型別安全:
// TypeScript 支援多種模組系統與 Node.js/瀏覽器執行
export function toUpperCase(str: string): string {
return str.toUpperCase();
}
ChatGPT 提示設計實例:從靈感到結構輸出
這是我常用來讓 ChatGPT 幫忙產生符合 TypeScript 型別的 mock 資料(包含 API response)的 prompt 實例:
請根據下方 interface,生成三筆用戶 mock 資料,並以 JSON 格式輸出:
interface User {
name: string;
age: number;
email: string;
}
你也可以讓它設計更複雜的 API 回應,像這樣:
請協助產生一份符合下方型別的 API 回應 mock 資料,需包含兩筆貼文,請用 JSON 輸出:
interface Post {
id: string;
title: string;
content: string;
author: User;
}
interface User {
name: string;
age: number;
}
工具鏈與開發體驗
配合 VS Code,TypeScript 提供自動補全、型別即時提示與導航功能,讓你和 AI 合作產生的程式碼,從一開始就大幅降低 bug 機率,打造乾淨可控的開發流程。這大大提升程式碼品質,降低維護成本。
總結而言,TypeScript 不只是「寫給電腦看的型別標籤」,更是 Vibe Coding 的核心工程基石。它讓 ChatGPT output 自動對齊你的設計規範,把 vibe code 從靈感的火花,轉化為可驗證、可維護、可協作的產品級程式碼。只要善用 TypeScript,無論 AI 多會寫 code,都能讓你的專案穩如泰山、不再踩雷。
Zod:型別約束的強化工具
在現代軟體開發流程中,尤其是 AI 驅動的 Vibe Coding 或自動化生成程式碼時,「型別安全」與「資料驗證」成為工程師最關心的核心議題。TypeScript 雖然提供了靜態型別檢查,但一旦進入執行階段,來自外部 API、用戶輸入或 AI 輸出的資料,仍可能出現型別不符、結構不完整等問題。這時候,Zod 就成為強化型別邊界的最佳解方。
為什麼選擇 Zod?
Zod 是一款專為 TypeScript 打造的宣告式資料驗證與型別推斷工具,徹底解決了「TypeScript 只能在編譯階段把關資料型別,但執行時無法驗證實際資料結構」的痛點。傳統 TypeScript 開發中,型別僅存在於編譯期,運行時無法確保外部 API、用戶輸入、AI 輸出等資料來源的正確性,這會導致潛在 bug 滲透到業務邏輯甚至生產環境。
Zod 讓開發者能以清晰、宣告式的語法一次性定義資料 schema,這個 schema 同時具備兩大功能:
- 靜態型別推斷:Zod 支援用
z.infer
自動推導出 TypeScript 類型,讓你免除重複維護型別與驗證規則的麻煩,任何 schema 變動都能即時反映在型別提示上,型別安全無縫貫穿整個專案。 - 執行時驗證:Zod schema 能在執行階段即時驗證資料的類型、結構、格式和約束條件,第一時間攔截不正確的資料來源,給出詳盡錯誤回饋,徹底彌補 TypeScript 僅於編譯階段檢查的不足。
結合型別與執行時驗證,Zod 為來自 API、AI 或表單的資料加上雙重保險,讓你更安心地處理各種動態來源,拒絕髒資料入侵核心邏輯。同時,Zod 的型別提示、 IDE 自動補全與嚴謹的執行時資料驗證,顯著提升專案的健壯性與維護效率。Zod 的極簡 API、不可變設計與輕量體積,也讓其成為現代 TypeScript 專案不可或缺的型別安全利器。
安裝與基本用法
安裝 Zod 十分簡單:
npm install zod
# 或
yarn add zod
引入後,你可以像這樣定義一個基本 schema 並驗證資料:
import { z } from 'zod';
const UserSchema = z.object({
name: z.string().min(2, { message: "姓名至少兩個字" }),
age: z.number().int().min(0).max(120)
});
const data = { name: 'John', age: 30 };
// 執行時驗證(出錯會直接 throw)
UserSchema.parse(data); // 通過驗證
// 錯誤示例
try {
UserSchema.parse({ name: '', age: -5 });
} catch (e) {
console.error((e as z.ZodError).errors);
// [
// { message: '姓名至少兩個字', ... },
// { message: 'Number must be greater than or equal to 0', ... }
// ]
}
安全驗證:safeParse
為了更優雅地處理錯誤,你可以用 safeParse
,它不會 throw,而是回傳一個結果物件:
const result = UserSchema.safeParse({ name: "A", age: 150 });
if (!result.success) {
result.error.errors.forEach(issue => {
console.log(`欄位 ${issue.path.join('.')}: ${issue.message}`);
});
}
型別自動推斷:z.infer
Zod 的最大亮點之一,是 schema 與 TypeScript 類型的自動同步。只需一行 code,就能從 schema 推斷出型別,確保資料結構與驗證規則永遠一致:
type User = z.infer<typeof UserSchema>;
// 編譯期型別安全
const user: User = {
name: "Jane",
age: 25,
// gender: "female", // ❌ 編譯錯誤,schema 未定義
};
進階應用:巢狀物件、陣列、Enum
Zod 支援複雜結構的模式定義及驗證:
const ArticleSchema = z.object({
id: z.string().uuid(),
title: z.string(),
tags: z.array(z.string()),
status: z.enum(["draft", "published", "archived"]),
author: UserSchema,
createdAt: z.date(),
});
與 AI 與 API 整合的實戰場景
假設你要驗證 AI 或第三方 API 回傳的資料,Zod 能直接當作資料防火牆,有效避免髒資料污染主流程。以下範例將長程式碼拆分為易讀步驟,每一段都有說明,協助你理解如何逐步處理驗證與錯誤回饋。
步驟 1:定義資料結構 Schema
先明確定義你預期收到的資料格式:
import { z } from 'zod';
const ArticleSchema = z.object({
id: z.string().uuid(),
title: z.string(),
tags: z.array(z.string()),
status: z.enum(["draft", "published", "archived"]),
author: z.object({
name: z.string(),
email: z.string().email(),
}),
createdAt: z.date(),
});
步驟 2:驗證 API 回傳資料並細緻處理錯誤
用 safeParse
驗證資料,不丟例外,而是彙整所有錯誤細節,便於紀錄與回饋:
async function handleApiResponse(raw: unknown) {
const result = ArticleSchema.safeParse(raw);
if (!result.success) {
// 彙整所有驗證失敗細節
result.error.errors.forEach(issue => {
console.error(
`欄位 ${issue.path.join('.')}:${issue.message}(收到值:${JSON.stringify(issue.received)})`
);
});
// 合併所有錯誤訊息
const message = result.error.errors
.map(issue => `欄位 ${issue.path.join('.')}:${issue.message}`)
.join("; ");
throw new Error("API 回傳資料格式錯誤:" + message);
}
// result.data 已型別安全且結構完整
return result.data;
}
步驟 3:串接流程,確保資料可靠
實際使用時,把驗證流程接在 API 輸入點,確保主流程只處理乾淨資料:
async function main() {
try {
const apiData = await fetchSomeApi();
const article = await handleApiResponse(apiData);
// article 型別安全,可直接使用
console.log("正確資料:", article);
} catch (e) {
console.error("資料驗證失敗:", e);
}
}
使用 safeParse
可以讓你在應對 AI 或第三方 API 不穩定、格式可能變動時,提前攔截並細緻記錄錯誤,大幅提升專案穩健性與資料可追蹤性。這種做法特別適合大型應用、AI 輸出驗證、或任何高可靠性場景。
與前端表單驗證、tRPC、React 深度整合
Zod 可與 React Hook Form、tRPC 等框架無縫協作,從表單輸入到 API 輸出全都型別一致、驗證一致。例如在 tRPC 中:
import { createRouter } from '@trpc/server';
const router = createRouter()
.mutation('registerUser', {
input: UserSchema,
resolve({ input }) {
// input 型別、結構已經過 Zod 驗證
return { ok: true };
}
});
自從引入 Zod,我對於 ChatGPT 或外部 API 輸入的資料更加安心。Zod 不只讓 vibe code 維持敏捷開發的速度,更大幅提升了安全性與可靠性。特別是處理 ChatGPT 輸出的 JSON 結構時,我習慣用 Zod 搭配 safeParse 進行格式驗證,這樣不僅能把關資料品質,也讓除錯過程更明確、更有效率。
JSDoc:提升可讀性,讓 AI 與團隊都能無痛維護
在大型專案或長期維護的程式碼庫中,最常見的痛點之一是「只有原作者懂」的黑盒邏輯。像是複利利息的計算函數,命名隨性、缺乏註解,不僅讓維護者摸不著頭緒,連 AI 也難以自動產生型別提示或測試案例。這就是典型的 legacy code,生產力與信心雙雙受挫。
改寫前:難以理解的黑盒函數
在許多舊有程式碼中,常見到類似下方這樣的黑盒函數:
function cal(p, r, n) {
return p * Math.pow(1 + r, n);
}
這樣的寫法雖然簡潔,卻藏有多重工程風險。首先,p
、r
、n
這些參數名完全沒有語意,需要額外猜測才能知道各自代表什麼意思。其次,函數缺乏型別註記與說明註解,導致後續維護者無法得知輸入資料的單位、範圍或任何邊界條件。這讓團隊成員或 AI 工具難以自動產生 API 文件、型別提示,甚至難以正確生成單元測試。最終,這種黑盒式設計會讓程式碼逐漸變得難以維護、擴充與協作,成為團隊生產力的絆腳石。
改寫後:JSDoc 結構化註解,現代化複利計算
在現代軟體開發中,清晰的註解和嚴謹的型別標註對於維護、協作與自動化生成文件至關重要。透過 JSDoc 結構化註解,我們不僅能為團隊成員提供即時的型別提示,也讓 AI 工具得以正確理解每個函數的用途與邊界條件。以下以複利計算函數為例,展示如何以現代工程標準撰寫註解與型別約束:
/**
* 計算複利後的本金總額。
*
* 公式:finalAmount = principal × (1 + rate) ^ periods
*
* @param {number} principal - 初始本金(非負數字)。
* @param {number} rate - 單期利率(小數,如 0.05 代表 5%)。
* @param {number} periods - 期數(非負整數)。
* @returns {number} 最終金額。
* @throws {TypeError} 參數型別或數值不正確時拋出錯誤。
* @example
* // 本金 1000 元,年利率 5%,複利 3 年
* calcCompoundInterest(1000, 0.05, 3); // 回傳 1157.625
*
* // 本金 5000 元,年利率 3%,複利 0 年
* calcCompoundInterest(5000, 0.03, 0); // 回傳 5000
*/
function calcCompoundInterest(
principal: number,
rate: number,
periods: number
): number {
if (typeof principal !== 'number' || principal < 0) {
throw new TypeError('principal 必須為非負數字');
}
if (typeof rate !== 'number' || rate < 0) {
throw new TypeError('rate 必須為非負數字');
}
if (!Number.isInteger(periods) || periods < 0) {
throw new TypeError('periods 必須為非負整數');
}
return principal * Math.pow(1 + rate, periods);
}
透過結構化 JSDoc 註解,函數的參數、回傳值、異常情況與使用範例都能一目了然。這不僅降低了團隊上手維護的門檻,也讓 AI 工具能自動產生型別提示與文件,顯著提升代碼品質與協作效率。將註解視為工程流程的一部分,才能讓程式碼真正具備可讀性、可維護性與現代化標準。
JSDoc 帶來的工程紅利
運用 JSDoc,不僅能讓函數自動推斷和檢查如負數本金、非數值利率、負期數等各種邊界條件,更能建立一致且結構化的 API 文件和型別提示。這大幅降低了團隊溝通與維護的成本,使新進成員、AI 工具,甚至跨部門協作者,都能快速理解並正確使用程式碼。
與其說 JSDoc 是註解工具,不如說它是人類與 AI 在程式碼溝通上的共同語言,幫你建構出可以被未來理解的邏輯結構。為關鍵函數與類別撰寫結構化註解,相當於為產品品質與團隊協作效率奠定堅實基礎。別讓 legacy code 成為團隊前進的阻礙——善用 JSDoc,讓你的 vibe code 輕鬆升級為每個人與 AI 都能理解、維護的現代高品質程式碼!
Vitest:驗證與回歸測試,讓 vibe code 立刻「驗證上線」
實踐 Vibe Coding,不能只靠靈感,更需要嚴謹的測試保障。我也經常讓 ChatGPT 幫我生成測試函式,透過描述 input/output 與邊界條件,它能快速給出接近可用的測試草稿。而有了 Vitest 的支援,這些草稿可以即時被驗證與調整,成為實戰等級的測試案例。現代化的測試工具如 Vitest,讓每一次 AI 產生或 refactor 的程式碼,都能即時驗證正確性,快速捕捉潛在錯誤。測試不該只是開發尾聲的例行公事,而應成為每段 AI 程式碼的品質保證機制,確保靈感能穩定變現,不被 bug 拖垮。
// 以 Vitest 測試簡單加法函數為例
function add(a: number, b: number): number {
return a + b;
}
import { describe, it, expect } from 'vitest';
describe('add', () => {
it('should return sum of two numbers', () => {
expect(add(2, 3)).toBe(5);
});
it('should handle negative numbers', () => {
expect(add(-2, 3)).toBe(1);
});
});
優勢
自動測試是現代軟體工程不可或缺的基石,尤其在 AI 協作與 Vibe Coding 的流程中扮演關鍵角色。它讓開發者能夠大膽地 refactor、重構,甚至放心採用 AI 生成的新邏輯,而無需擔心潛在的破壞性修改。無論是人類工程師還是 AI 工具,每當有新程式碼產生或既有邏輯被自動重寫時,自動化測試都會即時揭露問題,猶如一位始終在線的品質守門員,主動防堵 bug 滲透到產品之中。
在這樣的測試文化下,AI 生成—測試—優化形成高速的工程循環。開發者與 AI 可以在安全防護網下盡情嘗試新想法,測試機制則負責自動驗證每次的修改是否符合預期,讓人為疏漏與上線風險降到最低。這不僅提升了交付效率,更大幅縮短了從概念驗證(POC)到產品上線的週期。
更進一步,當測試涵蓋率足夠高時,AI 甚至可以根據現有測試自動產生新的代碼(test-driven code generation),或自動 refactor 現有邏輯而不破壞功能。這讓 Vibe Coding 從「靈感即興」進化為「可驗證、可持續」的工程流程,每一次 AI 協作都能在嚴謹的品質保障下安全落地。團隊可以持續積極地創新,同時確保每一次部署都穩定、可靠,最終實現創新速度與產品品質的雙贏。
結語
走過這段 AI 賦能的 Vibe Coding 之路,我深刻體會到:寫程式不再只是孤獨的腦力激盪,而是人與機器協作、靈感與工程並重的新旅程。ChatGPT 可以即時給我靈感、寫出 prototype,TypeScript 和 Zod 幫我把關型別與資料安全,JSDoc 讓團隊和 AI 彼此理解,Vitest 為每一次意外多上一層保護網。這些現代工程工具,讓我能放心地追逐創意,因為每一步都能被驗證、維護、傳承。
最令我感動的是,從前那種「只有自己懂」的焦慮漸漸消失了。現在的我,敢於大膽讓 ChatGPT 幫我寫 code,因為有型別、驗證、註解和測試的保駕護航,每段 vibe code 都能逐步進化為高品質的產品級程式碼。每次看到測試都綠燈、型別檢查通過時,我知道這不只是靈感的實現,更是團隊彼此信任與協作的結晶。
未來的軟體開發,不會是人類和 AI 的競爭,而是攜手共創的藝術。當我們善用這些工程基石,AI 不再只是工具,而是夥伴。願每位工程師都能在這條路上,寫出既有靈魂又可靠的程式,讓創意和品質彼此成就,開創真正屬於這個時代的工程新篇章。
如果你有 AI 專案、網站開發或技術整合需求,歡迎來信交流: partner@calpa.me
歡迎訂閱 Calpa 的頻道,一同將想像力化為可能: