AI 寫的程式總是出錯?我用 TypeScript + 函數式設計讓它聽得懂!

作者: Calpa Liu
字數:2709
出版:2025 年 5 月 4 日
你有遇過 AI 產生的程式碼完全跑不起來嗎?我曾經寫了一段計數器邏輯,結果它怎麼都看不懂。直到我用 TypeScript + 函數式設計重構,才發現——問題不在 AI,而是我們寫得不夠清楚。

你有沒有遇過這種狀況:請 AI 改個小功能,它改得亂七八糟,跑都跑不起來?

我以前也以為是 AI 太笨,後來才發現——是我寫得太亂。直到我用 TypeScript + 函數式設計重構,AI 才終於能幫上忙,連我自己 debug 也輕鬆多了。

TypeScript 能夠透過型別註解和純粹的小函數拆解,讓程式碼結構變得清晰且可預測,大幅提升 AI 理解與生成代碼的能力,也讓團隊協作和維護更加有效率。LLM 藉由 TypeScript 的型別資訊自動辨識資料流與函數結構,結合宣告式、無副作用的函數式風格,讓語意表達明確,進一步提升 AI 生成高品質代碼的能力。

📌 本文將帶你從一段常見錯誤寫法出發,透過 TypeScript 型別註解與函數式思維,轉化為 AI 更易理解、你也更易維護的現代程式設計範式。

為什麼 AI 看不懂你寫的程式?

你是不是也曾有過類似經驗:明明覺得自己寫得「很合理」,但 AI 卻無法正確補完、改寫、甚至回答你的提問?

問題往往不在於 AI 模型太笨,而是你的程式碼結構對 AI 來說太「不透明」——資料流混亂、副作用太多、邏輯分散在不同區塊,導致它無法清楚建立起「輸入 → 處理 → 輸出」的模型理解。

AI 生成程式碼時,最怕遇到不透明的狀態變動或隱藏的副作用——它無法確定資料何時、在哪裡被修改,也無法保證每次執行結果一致。這種不確定性讓 AI 難以安全重構邏輯或產生可預期的程式。函數式設計正好解決這個問題:它強調純函數、資料不可變和明確的資料流,讓 AI 能輕鬆理解每個步驟,生成更穩定、可重複的代碼。

來看一個常見例子:我們想計算所有用戶的訂單總額,同時記錄每筆訂單的處理過程。以下是典型寫法:

class OrderCalculator {
  constructor(users) {
    this.users = users;
  }

  getTotalAmount() {
    let sum = 0;
    for (const user of this.users) {
      for (const order of user.orders) {
        sum += order.amount;
      }
    }
    return sum;
  }

  getOrderLogs() {
    const logs = [];
    for (const user of this.users) {
      for (const order of user.orders) {
        logs.push(`Added order ${order.id} (${order.amount})`);
      }
    }
    return logs;
  }
}

// 使用場景舉例
// 假設在一個後端服務中,我們需要根據資料庫查詢結果來計算所有用戶的總訂單金額,並記錄每筆訂單的累加過程。
const users = [
  { id: "u1", orders: [{ id: "o1", amount: 100 }] },
  { id: "u2", orders: [{ id: "o2", amount: 50 }, { id: "o3", amount: 75 }] }
];

const calculator = new OrderCalculator(users);
const total = calculator.getTotalAmount(); // 225
const log = calculator.getOrderLogs();

console.log(log); // ["Added order o1 (100)", "Added order o2 (50)", "Added order o3 (75)"]
console.log(total); // 225

這段程式碼雖然「能跑」,但對 AI 而言有幾個難以處理的特徵:

  • 依賴類別內部狀態(this.users),使資料流不明確
  • 多層巢狀邏輯與副作用(log 組裝與計算混在一起)
  • 程式意圖需靠閱讀整段才能推論,不利於 AI 斷點理解與補完
  • 這樣的寫法對 AI 來說,就像在看一個沒有章法的流程圖 —— 它可以「模糊理解」,但無法保證產出邏輯正確、可維護的代碼。

那如果換成 TypeScript 結合函數式設計呢?效果會是什麼樣?我們來比較看看。

type Order = { id: string; amount: number };
type User = { id: string; orders: Order[] };

const getUserOrders = (users: User[]): Order[] => users.flatMap(user => user.orders);
const sumOrders = (orders: Order[]): number => orders.reduce((sum, o) => sum + o.amount, 0);

const getTotalAmount = (users: User[]): number =>
  sumOrders(getUserOrders(users));

// --- 使用範例 ---
const users: User[] = [
  { id: "u1", orders: [{ id: "o1", amount: 100 }] },
  { id: "u2", orders: [{ id: "o2", amount: 50 }, { id: "o3", amount: 75 }] }
];

const total: number = getTotalAmount(users); // 225

這段程式高度宣告式(declarative),清楚表達「先攤平成所有訂單,再累加金額」。資料流與變數型別明確,AI 能輕易辨識每個步驟的語意,生成與維護都更加簡單。這就是 TypeScript 型別與函數式拆解,如何幫助 LLM 更好地讀懂與生成程式碼的關鍵。

換句話說,清晰的型別、拆解的邏輯與純函數設計,讓 LLM 能聚焦於每個步驟的「意圖」而非流程細節,大幅提升程式碼協作與自動生成的品質與可靠性。

下面這組測試案例展示了 getTotalAmount 函數的各種情境,從單一使用者、多個使用者到空陣列,確保其正確累加所有訂單金額,並能處理沒有訂單或用戶的情況:

import { describe, it, expect } from "vitest";

describe("getTotalAmount", () => {
  it("能正確加總單一使用者的所有訂單金額", () => {
    const users: User[] = [
      { id: "a", orders: [{ id: "o1", amount: 20 }, { id: "o2", amount: 30 }] }
    ];
    expect(getTotalAmount(users)).toBe(50);
  });

  it("能略過沒有訂單的使用者,只加總有訂單的金額", () => {
    const users: User[] = [
      { id: "a", orders: [] },
      { id: "b", orders: [{ id: "o3", amount: 10 }] }
    ];
    expect(getTotalAmount(users)).toBe(10);
  });

  it("能處理空的使用者陣列,回傳 0", () => {
    expect(getTotalAmount([])).toBe(0);
  });
});

這些測試有助於確保你的累加邏輯既簡潔又健壯,也能作為 AI 工具理解與推理的高品質樣板。

TypeScript:AI 協作的理想語言

TypeScript 是 JavaScript 的超集,為動態語言世界帶來了靜態型別、結構化程式設計和先進的型別推斷能力。這些特性不僅讓人類開發者寫出更安全、可維護的程式碼,也讓 LLM(大型語言模型)更容易理解、推理與生成高質量的代碼。

靜態型別如何幫助 AI 精準推理

TypeScript 的型別註解讓變數、參數和返回值都明確標註型別,大幅降低語意歧義。LLM 理解與生成邏輯時,可以根據型別約束自動排除錯誤推論:

function add(a: number, b: number): number {
  return a + b;
}
// LLM 可從型別自動推導參數與回傳值,減少出錯

即使在複雜資料結構下,型別系統依然能提供強大的安全保障:

interface User {
  id: string;
  name: string;
  email?: string;
}

function getUserName(user: User): string {
  return user.name;
}

與 JavaScript 完美兼容,無縫接軌現有生態系

TypeScript 原生支援將代碼編譯為標準 JavaScript,開發團隊可無痛遷移、漸進升級。這讓 LLM 生成的 TypeScript 程式碼可以直接與現有 JS 專案融合,不必擔心生態斷層。舊有 JavaScript 檔案可逐步轉換,享受型別保障的同時維持生產力。

// TypeScript 支援多種模組系統與瀏覽器/Node.js 執行環境
export function toUpperCase(str: string): string {
  return str.toUpperCase();
}

泛型與推斷:讓 AI 寫出可重用的好程式

TypeScript 支援泛型和強大的型別推斷,讓程式碼高度抽象且安全,LLM 能生成適用於多種情境的泛用邏輯,提升可重用性:

function mapArray<T, U>(arr: T[], fn: (item: T) => U): U[] {
  return arr.map(fn);
}

const numbers = [1, 2, 3];
const strings = mapArray(numbers, n => n.toString());

除了函數泛型,TypeScript 也支援介面與類別泛型,讓複雜結構更安全:

interface ApiResponse<T> {
  data: T;
  error?: string;
}

提升協作與維護性

靜態型別與明確接口(interface/type)設計,讓多位開發者協作時規格一致、易於溝通,LLM 生成的程式碼可自動接受型別檢查,減少潛在錯誤並提升維護效率。例如:

type Point = { x: number; y: number };
function move(p: Point, dx: number, dy: number): Point {
  return { x: p.x + dx, y: p.y + dy };
}

強大的 IDE 支援與自動補全

TypeScript 丰富的型別資訊使主流 IDE(如 VS Code)能提供即時型別提示、錯誤警告、重構工具與自動補全,不僅提升人類開發效率,也讓 LLM 生成更精準、上下文正確的程式片段。常見支援功能包括:

  • 參數與返回型別即時提示
  • 自動導入與補全
  • 型別錯誤即時標註
  • 智能重命名與重構

複雜篩選邏輯

在實際業務中,資料篩選往往不止是簡單的遍歷,而是涉及多層結構的累加、判斷與資料抽取。當你需要從一群用戶中找出「訂單總額超過 100」的用戶 id,這種邏輯在大型專案或 AI 輔助開發時尤其常見。命令式寫法與聲明式(函數式)寫法的差異,會直接影響程式碼的可讀性、可維護性,甚至影響 AI 理解與自動生成程式碼的能力。

命令式寫法:

const richUsers2: string[] = [];
for (const user of users) {
  let sum = 0;
  for (const order of user.orders) {
    sum += order.amount;
  }
  if (sum > 100) {
    richUsers2.push(user.id);
  }
}

命令式寫法強調「每一步怎麼做」——你必須顯式建立暫存變數、手動累加、再檢查條件並 push 結果。每個細節都暴露給閱讀者,變數狀態容易混亂,維護時必須追蹤所有中間狀態與副作用。

函數式寫法:

const hasTotalOrderAmountOver100 = (user: User): boolean =>
  user.orders.reduce((sum, order) => sum + order.amount, 0) > 100;

const getUserId = (user: User): string => user.id;

const richUserIds = users
  .filter(hasTotalOrderAmountOver100)
  .map(getUserId);

函數式寫法直接表達「找出訂單總額超過 100 的用戶 id」這個意圖。資料流以鏈式處理,無需中間變數或副作用,邏輯聚焦,一目了然。這種寫法不僅讓人類工程師更容易理解,也讓 AI 更能精確推理資料流與運算重點。

在 AI 輔助開發的時代,優先採用聲明式、純函數的資料處理方式,不只提升可維護性,也讓自動生成、重構與測試更加容易,是現代軟體開發的核心實踐。

結論

不論你是剛踏入開發領域的新手,還是經驗豐富的工程師,只要想提升個人生產力、打造穩健可維護的團隊程式碼,TypeScript 結合函數式設計,絕對是 AI 時代最值得投資的技術路線。這套思維不僅讓我們寫出更安全、好懂、好維護的程式,也讓 LLM(大型語言模型)更容易理解我們的意圖,產出高品質、可協作的代碼。

我不會說這是「最快」的寫法,但每當我用這種型別明確、資料流清晰的方式請 AI 幫忙時,信任感和產出品質真的大幅提升。如果你也常常覺得 AI 不懂你、產生的程式碼難以維護,非常建議試著用這種思維重寫看看,說不定會成為你開發效率的轉捩點。

下次你遇到寫不動、AI 無法理解的程式,不妨試著換個思維,讓每個小函數都更純粹、更具語意。你會發現,AI 不只更懂你,連你自己也更懂自己在寫什麼。當我們把邏輯寫給人看的同時,也要寫給 AI 看——而 TypeScript + 函數式設計正是這座橋樑。

關於 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 助力,助你深入解析性格、事業、財務與人際課題。免費使用,適合命理師及紫微愛好者。
PixAI Prompt 組合器|快速打造可用於 AI 繪圖的語言拼圖
使用 PixAI 卻不會寫 prompt?這個工具幫你一鍵組裝角色、表情、風格語彙,輸出高品質繪圖提示語句(Prompt),可直接貼入 PixAI 使用。適合插畫師、創作者、AI 新手與 VTuber 角色開發者。