跳到主要內容

FE Day 3 TypeScript 基礎:型別系統與 tsconfig



FE Day 3 TypeScript 基礎:型別系統與 tsconfig

執行需求:CPU 可跑。今天是「前端開發實戰:React 與 Next.js 全套」系列的第三篇,前兩天把工具鏈蓋好了,從今天起我們把注意力轉到「寫程式本身」:TypeScript 的型別系統、tsconfig.json 的關鍵設定、以及「為什麼 React 專案幾乎都把 strict 打開」。讀完這一篇,你應該能用 TypeScript 描述函式參數、元件 props、API 回傳的資料形狀,並且在編譯器報錯時知道怎麼讀訊息。整篇大約三十分鐘,動手做約二十分鐘。

引言

後端工程師對「型別」一點都不陌生:Python 有 type hint(def add(a: int, b: int) -> int)、Java 與 Go 從一開始就是強型別。TypeScript 把這個觀念搬進 JavaScript:寫的時候要標型別,編譯器會在「執行前」就把型別錯誤找出來,執行階段反而更穩。這也是為什麼大型前端專案(以及 Next.js、React、Vue 3 的核心原始碼)幾乎都改用 TypeScript 重寫——型別即契約,能減少一半以上的溝通成本。

今天的目標有四個:第一,理解 TypeScript 的「結構型子型化」(structural typing)跟 Java「名字型子型化」(nominal typing)的差別;第二,把 tsconfig.json 的關鍵選項(strict、target、module、moduleResolution、jsx、noUncheckedIndexedAccess)逐一說明;第三,學會用型別註記描述基本資料(原始型別、陣列、元組、物件、函式);第四,認識 interface 與 type 的差異,並知道什麼時候該用哪個。最後我們會把以上觀念整合成一份「預約系統」的型別檔,這份檔案會從 Day 4 一直被沿用到 Day 45,先把基礎打好。

TypeScript 的型別哲學:結構型 vs 名字型

Java 與 C# 的子型化是「名字型」:兩個 class 名稱不同,就算欄位一模一樣也不算同一個型別。TypeScript 走的是「結構型」:只要形狀(structure)一樣,就被視為相容。後端工程師第一次接觸會覺得「這也太鬆了吧?」,但實際寫 React 元件時非常方便——你只要描述「這個 props 應該長什麼樣」,呼叫端只要照著填就好,不必繼承某個 base class。

舉個例子:

// src/types.ts
// TypeScript 的「結構型子型化」示範
type User = {
  id: number;
  name: string;
};

type Admin = {
  id: number;
  name: string;
  role: "owner" | "editor";
};

function greet(user: User) {
  console.log(`Hello, ${user.name}`);
}

const admin: Admin = { id: 1, name: "Hao", role: "owner" };

// TypeScript 不會報錯:admin 的形狀包含 User 的所有欄位
greet(admin);
// 輸出:Hello, Hao

這個例子裡 Admin 多了 role 欄位,但因為它「擁有 User 所有的欄位」,所以 greet(admin) 是合法的。如果用 Java 的觀念看會覺得奇怪(Admin 不是 User 的子類別),但在 TypeScript 的世界裡,這就是它鼓勵的設計:型別只看結構,不看名字。後端寫過 Go 介面的工程師會覺得熟悉——Go 的介面也是結構型(duck typing),不需要明確宣告實作。

結構型的好處在 React 元件設計上特別明顯。假設你寫了一個 Avatar 元件,呼叫端不需要先把 user 宣告成某個 base class 再繼承,只要它「至少有 id 跟 name」就能用。這種設計讓元件的依賴維持在「最低必要欄位」而不是「特定類別」,重構時更不容易壞。

tsconfig.json 的關鍵選項

昨天我們用 Vite 範本建立專案時,TypeScript 幫我們生成了一份 tsconfig.json。今天把它拆得更細,理解這些選項背後的設計理念,能讓你在新專案、monorepo、SSR 環境之間切換時不會卡住。

選項 推薦值 為什麼
target ES2022 對應 Node 22/24 與主流瀏覽器(Chrome 94+、Safari 16+、Firefox 93+)
lib ["ES2022", "DOM", "DOM.Iterable"] DOM 函式庫讓你能用 document、fetch 等瀏覽器 API
module ESNext 與 type: "module" 配合,輸出原生 ESM
moduleResolution bundler 對應 Vite、Next.js、webpack 5+ 的解析規則;可以省略副檔名
jsx react-jsx React 17+ 自動 runtime;不需要每支檔案 import React
strict true 打開後啟用 strictNullChecks、noImplicitAny 等 8 個子選項
noUncheckedIndexedAccess true 陣列取值會回傳 T | undefined,逼你處理空值
exactOptionalPropertyTypes true field?: string 不再允許被設成 undefined 顯式值

其中 strict: true 是最重要的一個開關。打開後,TypeScript 會啟用 8 個子選項:noImplicitAny(不允許隱式 any)、strictNullChecks(null/undefined 要明確處理)、strictFunctionTypes(函式參數嚴格比對)、strictBindCallApply(bind/call/apply 型別嚴格)、strictPropertyInitialization(class 屬性必須初始化)、noImplicitThis(this 必須有明確型別)、useUnknownInCatchVariables(catch 變數預設 unknown)、alwaysStrict(輸出嚴格模式)。每一條都對應一個常見的 bug 模式。

用 strictNullChecks 示範嚴格模式

沒打開 strictNullChecks 之前,TypeScript 允許 string 變數被設成 null;打開之後,會被報錯:

// src/strict-null.ts
// strictNullChecks = false 時,這段不報錯
// strictNullChecks = true 時,這段會報錯
function getLength(s: string): number {
  return s.length;
}

// 編譯錯誤:Argument of type 'string | null' is not
// assignable to parameter of type 'string'.
getLength(null);

對後端工程師來說,這個行為跟 Java 對 null 的嚴格要求一致。打開 strict 之後,TypeScript 會逼你在呼叫前先檢查:

// src/strict-null.ts(修法)
function getLength(s: string | null): number {
  if (s === null) return 0;
  return s.length;
}

// 現在這個呼叫合法
getLength(null);
// 輸出:0

這個小習慣能擋掉一大堆「Cannot read property of undefined」這種經典 runtime 錯誤。後端寫過 Kotlin 或 Swift 的工程師會立刻有共鳴。

用 noUncheckedIndexedAccess 防呆

noUncheckedIndexedAccess 是 4.1 版加入的選項,預設關閉。把它打開之後,陣列取值會被推論成 T | undefined,強迫你處理「這個索引可能不存在」的情境:

// src/unchecked-index.ts
const items = ["apple", "banana", "cherry"];

// 沒打開 noUncheckedIndexedAccess:first 是 string
// 打開之後:first 是 string | undefined
const first = items[0];
console.log(first?.toUpperCase());
// 輸出:APPLE(沒有報錯,但加上 ?. 避免 undefined 時炸掉)

乍看之下很囉嗦,但在真實應用裡非常實用:後端 API 回傳的陣列可能是空的、查詢參數的解析結果可能沒有對應值、字典取值永遠可能回傳 undefined。打開這個選項之後,你的程式碼會「天生」對空值有防呆。後端工程師寫過 Optional、Maybe、Result 的人會發現:這個選項背後的概念跟那些東西一模一樣,只是表現在陣列與物件存取上。

原始型別、陣列、元組、物件

TypeScript 的型別註記語法非常貼近日常寫法。後端工程師可以把它想成「在變數後面掛一個標籤,告訴編譯器『這個變數只接受這些形狀的值』」。下面把最常用的幾種型別整理成對照表與範例。

型別 語法 範例
布林值 boolean let active: boolean = true;
數字 number let count: number = 42;
字串 string let name: string = "Hao";
陣列 T[] 或 Array<T> let ids: number[] = [1, 2, 3];
元組 [T1, T2] let pair: [string, number] = ["age", 30];
物件 { field: T } let user: { id: number; name: string };
函式 (a: T) => U let add: (a: number, b: number) => number;
聯合型別 T1 | T2 let status: "ok" | "error";
可空 T | null let value: string | null = null;

這張表先記住,後續的範例會反覆用到。其中「聯合型別」(union types)是 React props 設計裡最常出現的技巧:「這個欄位可以是字串、也可以是數字」、「這個狀態可以是 loading、success、error」——這種「列舉幾種可能」的設計,TypeScript 用 | 連起來,編譯器會幫你檢查「所有分支都處理過」。對後端工程師來說,union 比 enum 更像「Python 的字面量聯合(Literal)」——輕量、明確、無須額外宣告。

物件型別:內聯 vs type alias

簡單的物件可以直接寫內聯型別,但只要同一個形狀出現第二次,就該抽出來用 type:

// src/user.ts
// 簡單的物件型別:先用內聯,第二次出現就抽 type
type User = {
  id: number;
  name: string;
  email: string;
  createdAt: Date;
};

function createUser(input: { name: string; email: string }): User {
  return {
    id: Math.floor(Math.random() * 1_000_000),
    name: input.name,
    email: input.email,
    createdAt: new Date(),
  };
}

const u = createUser({ name: "Hao", email: "hao@example.com" });
console.log(u.id, u.name);
// 輸出:123456 Hao(id 隨機產生)

這段展示兩個觀念:第一,type User = { ... } 是 TypeScript 的「型別別名」,可以把複雜形狀命名後重複使用;第二,函式參數可以混用「內聯型別」與「type alias」,簡單的留內聯、複雜的抽出去。後端工程師可以把它理解成「Python 的 TypedDict 或 Pydantic 的 BaseModel」。

陣列與元組的差別

陣列是「同型別的多個值」,元組是「固定長度、每個位置型別已知」的結構。後端工程師可以把它想成「List vs tuple(Python)」:

// src/arrays.ts
// 陣列 vs 元組:長度與位置的差異
const numbers: number[] = [1, 2, 3];
const first: number = numbers[0];

// 元組:固定 [name, age] 的順序
const profile: [string, number] = ["Hao", 30];
const [name, age] = profile;

console.log(name, age);
// 輸出:Hao 30

// 元組 vs 陣列的實務差異:
// - 陣列:用 map / filter / forEach
// - 元組:用解構(destructuring)拿到對應位置的值

實務上 React 的 useState 回傳的就是元組:[value, setValue]。其他時候陣列比較常用,元組則出現在「需要明確幾個值」的情境(例如經緯度、HTTP status + 訊息、Python 常見的 (status_code, body) 回傳)。

interface 與 type 的差別

TypeScript 提供兩種描述物件型別的語法:interface 與 type。兩者 90% 的功能重疊,但有幾個細節差異值得記住:

// src/shapes.ts
// 兩種描述「使用者」型別的寫法
interface UserI {
  id: number;
  name: string;
}

type UserT = {
  id: number;
  name: string;
};

// 兩者在這個情境完全等價
const a: UserI = { id: 1, name: "Hao" };
const b: UserT = { id: 2, name: "Min" };

// interface 的特性:可以被「合併」(declaration merging)
interface UserI {
  email: string;
}
// 此時 UserI 變成 { id, name, email }
const c: UserI = { id: 3, name: "Hao", email: "x@y.com" };

幾個判斷原則:第一,描述物件或類別的「形狀」時,interface 與 type 都可以,看團隊慣例;第二,需要做「宣告合併」(同一個名字多次宣告,欄位會合併)時只能用 interface;第三,需要「聯合型別」(A | B)、「工具型別」(Pick<User, "id">)或「映射型別」時只能用 type。本系列一律用 type,因為 React 的 props 通常會用到 Pick、Omit 等工具型別,type 用起來比較一致。

選用 optional 欄位

React props 大部分時候都有「可選欄位」(onClick?: () => void)。TypeScript 用 ? 標記:

// src/button-props.ts
// React 按鈕元件的 props 型別:大部分欄位是可選的
type ButtonProps = {
  label: string;            // 必填
  onClick?: () => void;     // 可選:沒傳就不綁事件
  variant?: "primary" | "secondary" | "ghost";  // 可選 + 聯合型別
  disabled?: boolean;       // 可選:預設 false
};

function Button({ label, onClick, variant = "primary", disabled = false }: ButtonProps) {
  return { label, hasOnClick: !!onClick, variant, disabled };
}

console.log(Button({ label: "送出" }));
// 輸出:{ label: '送出', hasOnClick: false, variant: 'primary', disabled: false }

注意兩件事:第一,onClick?: () => void 表示呼叫端可以不傳,也可以傳函式;第二,函式本體裡用解構預設值 variant = "primary",這是 TypeScript 處理「optional 欄位」的標準慣例。後端工程師可以把它對應到 Python 的 Optional[Callable[[], None]]。另外,當 exactOptionalPropertyTypes 打開時,呼叫端不能傳 undefined 給 optional 欄位——必須「不傳」或「傳值」,這對 React props 的語意更精準。

完整實作:為預約系統建立型別檔

把以上觀念整合起來,建立一個「預約系統」的型別檔。這個檔案會從 Day 4 一直被沿用到 Day 45,先把基礎打好:

// src/types/booking.ts
// 預約系統的核心型別:會被前端所有頁面與 API 層引用

// 預約狀態:列舉四種合法值,編譯器會檢查 switch 是否窮舉
export type BookingStatus = "pending" | "confirmed" | "cancelled" | "completed";

// 服務品項:對應 Web 系列 FastAPI 的 Service 模型
export type Service = {
  id: number;
  name: string;
  durationMinutes: number;
  price: number;
};

// 預約單:對應 Web 系列的 Booking 模型
export type Booking = {
  id: number;
  customerName: string;
  customerPhone: string;
  serviceId: number;
  startAt: string;        // ISO 8601,例如 "2026-03-20T10:00:00+08:00"
  status: BookingStatus;
  notes?: string;         // 顧客備註(可選)
  createdAt: string;
  updatedAt: string;
};

// 建立預約的輸入:省略 id / createdAt / updatedAt / status
export type BookingCreateInput = {
  customerName: string;
  customerPhone: string;
  serviceId: number;
  startAt: string;
  notes?: string;
};

// API 回應的包裝:對齊 FastAPI 的標準回應
export type ApiResponse<T> = {
  data: T;
  meta?: { total?: number; page?: number };
};

export type ApiError = {
  code: string;
  message: string;
  details?: Record<string, string>;
};

這段展示了四個實務技巧:第一,用字串聯合型別("pending" | "confirmed" | ...)表達「列舉值」,比 enum 更輕量;第二,把「建立輸入」與「完整資料」分開(BookingCreateInput 沒有 id / 時間戳記 / 狀態),呼應後端 Pydantic 的 Create vs Read schema;第三,ApiResponse<T> 用泛型包裝所有 API 回應,未來接 FastAPI 時可以一個型別對應所有 endpoint;第四,ApiError 把錯誤格式統一,UI 層就能用一致的方式處理錯誤訊息(Day 37 會展開)。

存檔後跑 pnpm typecheck,TypeScript 應該靜默通過。接著可以寫一支測試函式,確認型別真的會把關:

// src/types/booking.test-draft.ts
// 故意寫錯的版本:體驗編譯器的把關能力
import type { Booking, BookingCreateInput } from "./booking";

const ok: BookingCreateInput = {
  customerName: "王小明",
  customerPhone: "0912345678",
  serviceId: 1,
  startAt: "2026-03-20T10:00:00+08:00",
};

// 故意寫錯:phone 是空字串,serviceId 是負數
// 編譯器會報「Type '""' is not assignable to type 'string | undefined'」
// 但因為型別系統不檢查「值的合理性」,要靠 zod / valibot 等 runtime 驗證
const bad: BookingCreateInput = {
  customerName: "",
  customerPhone: "",
  serviceId: -1,
  startAt: "not-an-iso-date",
};

這段示範 TypeScript 的「邊界」:它能檢查「型別不符」(例如傳字串給 number),但不能檢查「值的合理性」(例如電話號碼格式、日期是否合法)。後者要靠 Zod、Valibot 等 runtime 驗證庫,Day 12 與 Day 21 會展開。

常見錯誤與踩雷

第一次用 TypeScript 寫程式,最常踩的雷有三個。第一個是「any 滿天飛」。很多新手遇到編譯錯誤第一反應是加 : any,結果 TypeScript 的保護全部失效。正確做法是先讀懂錯誤訊息,多半是「少標一個型別」、「忘記處理 null」這種小事;真的要逃脫型別檢查時,用 unknown(強迫你先檢查才能用)比 any 安全。

第二個是「把 interface 與 type 混用」。同一個專案裡,有人喜歡 interface、有人喜歡 type,結果程式碼風格不一致、增加 onboarding 成本。建議團隊在 README.md 或 STYLE.md 寫明「一律使用 type」,把規則講清楚。本系列一律用 type。

第三個是「忘了開 strict」。很多教學文章為了讓範例簡單,會把 strict: false。但只要專案變大、沒開 strict 帶來的 null/undefined bug 會遠超過「寫 strict 時多寫的兩行程式碼」。建議從 Day 1 就開 strict: true,並把 noUncheckedIndexedAccess、exactOptionalPropertyTypes 也打開,習慣之後寫什麼都會更安心。

效能與實務提醒

TypeScript 的型別檢查在大型專案會變慢。Vite 用 esbuild 做轉譯(不檢查型別),所以 dev server 啟動很快;但 tsc --noEmit 會掃全部檔案做完整檢查,檔案超過幾千個的時候可能要十幾秒。可以考慮用「增量編譯」或「專案參考」(project references)來加速:

{
  "compilerOptions": {
    "composite": true,
    "incremental": true
  }
}

incremental: true 會把上次的編譯結果存在 .tsbuildinfo,下一次只檢查有改動的檔案;composite: true 是 monorepo 才用得到,告訴 TypeScript「這個 tsconfig 是某個專案的入口」。本系列規模不大,Day 31 之後進入預約系統才會考慮這個。

另一個實務建議:把 tsconfig.json 拆成多份,對應不同的執行環境。React 前端用「瀏覽器 + ES2022」、Node.js 腳本用「Node + ES2023」、共享型別用「base」。

// tsconfig.json(根目錄,只是「專案參考」的入口)
{
  "files": [],
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ]
}
// tsconfig.app.json(瀏覽器端 React)
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "jsx": "react-jsx",
    "noEmit": true
  },
  "include": ["src"]
}
// tsconfig.node.json(Node.js 端,例如 vite.config.ts)
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "lib": ["ES2023"],
    "types": ["node"],
    "noEmit": true
  },
  "include": ["vite.config.ts"]
}

這份三層架構是 Next.js 預設的結構:根目錄只放 references、app 給瀏覽器、node 給伺服器腳本。Day 17 開始用 create-next-app 會直接生成這套,可以拿來對照。

怎麼讀 TypeScript 的錯誤訊息

第一次看到 TypeScript 報錯的人,常會被那一大段英文嚇到。其實大部分錯誤訊息只告訴你三件事:「出錯的位置」、「預期的型別」、「實際的型別」。只要讀懂這三欄,幾乎所有錯誤都能自己解。下面示範幾個常見訊息的解讀:

  • "Type 'string | null' is not assignable to parameter of type 'string'":你傳了一個可能是 null 的值給預期是 string 的參數。修法是先檢查 if (x !== null) 再用。
  • "Property 'foo' does not exist on type 'Bar'":你在一個物件上存取了一個它沒有的欄位。先確認型別定義,或是用 in 運算子先判斷。
  • "Object is possibly 'undefined'":因為 noUncheckedIndexedAccess,陣列或字典取值可能是 undefined。修法是用 ?. 或先檢查長度。
  • "Argument of type 'X' is not assignable to parameter of type 'Y'":函式呼叫的參數型別不符。要嘛改呼叫端、要嘛改函式簽章、要嘛中間加一層轉換。

讀懂錯誤訊息有一個小技巧:把訊息中的兩個型別抄到一行筆記裡(「我要把 X 放進 Y」),然後問自己「X 真的可以放進 Y 嗎?」。如果不能,要嘛改 X、要嘛改 Y、要嘛在中間做轉換。VS Code 把滑鼠移到紅色底線的變數上,會顯示更完整的推論路徑(Quick Info),這是新手最常忽略的除錯利器。

另一個實務技巧是「看錯誤碼」。TypeScript 5.x 的錯誤訊息前面會帶一個數字編號(例如 TS2322),這個編號對應到官方 issue tracker 裡的具體問題描述。遇到看不懂的錯誤,把 TS2322 丟到搜尋引擎,比直接讀英文訊息更有效率。本系列 Day 4 會介紹更多收窄技巧,讓你可以主動避開這些錯誤,而不是被動地修它。

小結

今天我們把 TypeScript 的基礎打底了:結構型子型化、tsconfig.json 的關鍵選項(含 strict 與 noUncheckedIndexedAccess)、原始型別、陣列、元組、物件、type 與 interface 的差別、optional 欄位的寫法,並建立了一份預約系統的核心型別檔。明天 Day 4 我們會把 TypeScript 推得更深:泛型(ApiResponse<T>、useState<T> 都需要它)、型別收窄(用 typeof、in、instanceof 把「可能是多種型別」的變數縮到一種)、以及工具型別(Pick、Omit、Partial、Readonly、Record)。到時候寫 React 元件時,「型別即契約」的威力就會完全展現出來。

結語

明天,我們會把 TypeScript 的進階語法一次學完:泛型讓你能寫「可重用的型別函式」、型別守衛(type guard)讓你在 runtime 縮小 union、工具型別讓你從現有型別衍生新形狀而不必重寫。Day 4 結束時,你應該能讀懂 React 與 Next.js 原始碼裡那些「型別簽名」,並且知道怎麼把這些技巧套用到自己的專案。Day 5 接著進入 React 入門——元件、props 與 JSX,正式從「型別」跨進「畫面」。

延伸資源

  • TypeScript Handbook〈The Basics〉(5.9):https://www.typescriptlang.org/docs/handbook/2/basic-types.html
  • TypeScript Handbook〈Everyday Types〉:https://www.typescriptlang.org/docs/handbook/2/everyday-types.html
  • TypeScript Handbook〈tsconfig.json〉:https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
  • TypeScript 官方 Cheat Sheets(含 React 範例):https://www.typescriptlang.org/cheatsheets
  • React 官方 TypeScript 指南:https://react.dev/learn/typescript

留言

這個網誌中的熱門文章

Day 2 變數與資料型別

Day 2 變數與資料型別 引言 寫程式的過程中,變數與資料型別是處理資料的基礎。變數是存放資料的容器,資料型別則決定這筆資料有哪些特性、可以進行哪些操作。學會定義變數、認識各種資料型別,是學好 Python 的關鍵一步。 這篇文章會帶你了解 Python 中變數的觀念、如何定義變數,以及常見的資料型別,包括整數、浮點數、字串、布林值,還有串列、元組、字典與集合等容器型別。我們也會介紹變數的命名規則與撰寫風格建議,以及如何用 type() 檢查資料型別。 什麼是變數?如何在 Python 中定義變數 變數是在程式執行時用來存放資料的名稱。透過定義變數,我們可以給一筆資料一個名字,並在程式的其他地方用這個名字取用該筆資料。在 Python 中,變數不需要事先宣告型別,因為 Python 是動態型別語言,變數的型別由指定給它的值決定。 定義變數的基本語法 在 Python 中定義變數非常簡單,只要用賦值符號 = 把值指定給變數即可。例如: x = 5 # 定義變數 x,並把整數 5 賦值給它 name = "Alice" # 定義變數 name,並把字串 "Alice" 賦值給它 在這裡,x 是一個變數,被賦予整數 5;name 是另一個變數,被賦予字串 "Alice"。 變數的更新與覆寫 變數的值可以修改,也就是說,我們可以在程式的不同地方給同一個變數新的值。例如: x = 10 # x 最初被賦予 10 x = 15 # x 的值現在被更新為 15 這樣就能依照需求,在程式執行過程中靈活調整變數的值。 Python 的動態型別系統 Python 和某些靜態型別語言不同,定義變數時不需要宣告型別。賦值時,Python 會根據值自動判斷變數的型別。例如: x = 5 # x 是整數 x = 3.14 # x 變成浮點數 x = "Hi" # x 變成字串 同一個變數在程式執行過程中可以存放不同型別的值,這是 Python 的彈性之一。 常見資料型別 在 Python 中,資料型別決定我們可以對變數進行哪些操作...

Day 1 Python 簡介與環境設定

Day 1 Python 簡介與環境設定 引言 在現在的科技環境裡,程式設計已經是一項重要技能。無論你是對資料科學有興趣、想成為開發者,或是想踏入人工智慧(AI)領域,學會寫程式都能明顯提升你的競爭力。在眾多程式語言中,Python 因為語法簡單、功能強大、應用範圍廣泛,成為許多人進入程式世界的第一選擇。這篇文章會帶你認識 Python 的背景與優勢,並一步步教你在不同系統上安裝與設定 Python 開發環境,最後寫出第一支 Python 程式。 為什麼選擇 Python? Python 是一種高階程式語言,由 Guido van Rossum 在 1991 年發布。Python 的設計哲學強調程式碼的可讀性,並用縮排來定義程式區塊,這點和許多使用大括號的語言不同。簡潔的語法讓它成為初學者的理想選擇;就算是經驗豐富的開發者,也能用它完成複雜的專案。 Python 的優勢如下: 簡單易學 :Python 的語法清楚、結構簡潔,初學者很快就能上手。和其他語言相比,學習曲線相對平緩,不需要先弄懂一堆複雜觀念,就能開始寫程式。 應用範圍廣泛 :從資料科學、網頁開發、人工智慧、機器學習、自動化測試到網路爬蟲,Python 都有大量開源函式庫與工具支援,而且在這些領域都扮演關鍵角色。 豐富的函式庫與框架 :Python 的函式庫生態系非常龐大。做資料分析有 NumPy、Pandas;開發網站有 Django、Flask;做深度學習有 TensorFlow、PyTorch。各種需求幾乎都能找到對應的套件,讓開發更有效率。 跨平台支援 :Python 支援 Windows、macOS、Linux 等作業系統,程式通常不需要太多修改就能跨平台執行,讓開發與部署更有彈性。 活躍的社群 :Python 擁有龐大的開發者社群。學習或開發上遇到問題,幾乎都能在社群與論壇(例如 Stack Overflow)找到答案,對初學者來說是很強的後盾,也能減少卡關時的挫折感。 Python 的應用領域 Python 的流行與強大功能,讓許多領域都開始大量使用它。以下是幾個常見的應用方向: 資料科學 :隨著大數據與人工智慧興起,資料科學大量使用 Python。NumPy、Pandas 與 Matplotlib 等工具能處理和分析龐...

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門 隨著人工智慧(AI)與深度學習(Deep Learning)快速發展,越來越多人對這些技術產生興趣。不論你是想踏入 AI 領域的初學者,還是已經有程式基礎的開發者,學好 Python 與深度學習框架(例如 PyTorch),都能為你打開更多可能。 為什麼選擇 Python? Python 已經是資料科學與人工智慧領域的首選語言。它的語法簡潔、容易上手,而且擁有龐大的生態系與大量開源函式庫。無論是資料處理、資料視覺化,還是建立機器學習與深度學習模型,Python 都能勝任。對想進入 AI 或資料科學領域的人來說,它幾乎是必備工具。 PyTorch 是什麼? PyTorch 是由 Meta(原 Facebook)AI 研究團隊開發的開源深度學習框架,以易用、靈活和動態計算圖著稱,是許多 AI 研究人員與開發者的首選。相較於其他框架,PyTorch 的寫法更貼近原生 Python,對初學者相對友善。無論是簡單的實驗,還是複雜的深度學習模型,PyTorch 都能提供強大的支援。 這個系列能帶給你什麼? 這個系列會從 Python 的基礎開始,帶你一步一步學習,最後能自己用 PyTorch 建立深度學習模型。即使你完全沒有寫過程式,也能跟著文章的節奏累積技能,理解 AI 與深度學習的核心觀念。 本系列涵蓋的主題 Python 基礎:從變數、條件判斷到函式與模組。 資料處理工具:用 NumPy 與 Pandas 有效率地操作資料。 資料視覺化:用 Matplotlib 與 Seaborn 把資料畫成圖表。 深度學習的數學基礎:線性代數、微積分與機率。 PyTorch 入門:理解張量、模型建構與 GPU 加速。 基礎深度學習模型:CNN 與 RNN 的實作應用。 深度學習專案實戰:從資料前處理到模型部署的端到端流程。 誰適合這個系列? 程式初學者 :如果你對 AI 充滿好奇,卻還沒寫過程式,系列的第一部分會帶你快速上手 Python,並幫助你理解深度學習的基本觀念。 資料科學愛好者 :如果你已經熟悉一些資料處理方法,進階部分會教你如何用 PyTorch 建構深度學習模型。 開發者與研究人員 :想更深入了...