AI 協作時代的軟體工程四神器:TypeScript、Zod、Vitest、JSDoc 實戰心得

作者: Calpa Liu
字數:4165
出版:2025 年 5 月 23 日
分類: AI TypeScript 軟體工程 前端開發
想用 AI 寫程式又怕爛 code?這篇文章分享我如何結合 ChatGPT、TypeScript、JSDoc、Zod 與 Vitest,打造可維護、可驗證的 Vibe Coding 流程,讓靈感不只是 prototype,而是真正能安全上線的產品級程式碼。

剛開始推廣 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 同時具備兩大功能:

  1. 靜態型別推斷:Zod 支援用 z.infer 自動推導出 TypeScript 類型,讓你免除重複維護型別與驗證規則的麻煩,任何 schema 變動都能即時反映在型別提示上,型別安全無縫貫穿整個專案。
  2. 執行時驗證: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);
}

這樣的寫法雖然簡潔,卻藏有多重工程風險。首先,prn 這些參數名完全沒有語意,需要額外猜測才能知道各自代表什麼意思。其次,函數缺乏型別註記與說明註解,導致後續維護者無法得知輸入資料的單位、範圍或任何邊界條件。這讓團隊成員或 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 不再只是工具,而是夥伴。願每位工程師都能在這條路上,寫出既有靈魂又可靠的程式,讓創意和品質彼此成就,開創真正屬於這個時代的工程新篇章。

關於 Calpa

Calpa 擅長使用 TypeScriptReact.jsVue.js 建立 Responsive Website。

他積極參與開源社區,曾在 2019 年的香港開源大會上擔任講者,提供工作經驗和見解。此外,他也在 GitHub 上公開分享個人博客程式碼,已獲得超過 300 顆星星和 60 個分支的支持。

他熱愛學習新技術,並樂意分享經驗。他相信,唯有不斷學習才能跟上快速演變的技術環境。

熱門文章

最新文章

圖片管理中心
管理圖片資源
IP 查詢
快速查詢和定位 IP 地址的地理位置和相關信息
Python 運行器
無需後端、無需登入,只需打開瀏覽器即可運行 Python 代碼(由 Pyodide 提供支持)
封面圖生成器
自動創建適合各種平台的文章封面圖
原作(青山剛昌)產生器
一鍵創建原作(青山剛昌)的封面圖
日本色彩
探索和使用傳統日本色彩
部落格內容洞察儀表板
以視覺化儀表板方式追蹤文章成效、分享熱度與分類分布,協助創作者掌握內容表現。
蒙特卡羅估算 π
使用蒙特卡羅方法演示 π 值的估算過程
LLM
使用 LLM 模型進行聊天
活動圖生成器
一鍵創建活動的封面圖
Wagmi Card
一鍵創建 Wagmi 的封面圖
Facebook Quote
Facebook Quote
Music Macro Language (MML) Studio
用程式語法編寫旋律,用音符構築想像
Blurhash
一鍵創建 Blurhash
文字分類器
使用 MediaPipe TextClassifier 分類文字
前端工程師免費工具資源
前端工程師免費工具資源
後端工程師免費工具資源
後端工程師免費工具資源
全端工程師免費工具資源
全端工程師免費工具資源
Web3 工程師免費工具資源
Web3 工程師免費工具資源
紫微斗數排盤系統|結合 AI 的命盤性格與事業財務分析生成器
紫微斗數排盤工具,輸入生日與時辰,自動生成完整命盤分析提示(Prompt)。結合最專業紫微理論與 AI 助力,助你深入解析性格、事業、財務與人際課題。免費使用,適合命理師及紫微愛好者。