TypeScript 型別註解 (Type Annotations)
型別註解是我們「明確告訴」TypeScript 這個變數是什麼型別的方式。雖然 TypeScript 很聰明(有強大的型別推論),但有這兩種情況我們通常會明確寫出型別:
- 當 TS 猜不到時(例如函式參數)。
- 當我們想強制檢查時(例如確保函式回傳值符合預期)。
基本語法
語法很簡單,就是在變數或參數後面加上 : 型別名稱。
變數註解 (Variables)
// 告訴 TS:這個 name 變數一定要是 string
let name: string = '小明';
// 錯誤!不能把 number 塞給 string
// name = 123;
小知識:其實上面這個例子不需要寫
: string,因為 TS 看到"小明"就知道它是字串了。這叫做「型別推論」,我們下一章會細講。
函式參數 (Detailed Functions)
這是最需要型別註解的地方!因為 TS 通常無法猜到你的函式會被怎麼呼叫。
// 定義:input 必須是 string
function logMessage(message: string) {
console.log(message);
}
// 使用正確
logMessage('Hello');
// 報錯:TS 阻止你傳入錯誤的型別
// logMessage(123);
函式回傳值 (Return Type)
我們也可以規定函式「必須」回傳什麼型別。
// 這個函式接收兩個 number,並且保證回傳 number
function add(a: number, b: number): number {
return a + b;
}
這在多人協作時特別好用,因為如果有人不小心改壞了函式邏輯(例如回傳了字串),TS 馬上會報錯。
複雜型別註解
陣列 (Arrays)
// 定義一個「只裝數字」的陣列
let numbers: number[] = [1, 2, 3];
// 錯誤!不能放字串進去
// numbers.push("4");
物件 (Objects)
我們可以直接在變數後面描述物件的「形狀」:
let user: {
name: string;
age: number;
} = {
name: '小明',
age: 25,
};
但通常我們會用 interface 或 type 把這個形狀抽出來,讓程式碼更乾淨:
interface User {
name: string;
age: number;
}
let user: User = {
name: '小明',
age: 25,
};
常見問題
Q: 什麼時候該寫註解?什麼時候靠推論?
原則:能推論就讓它推論,不能推論(或推論結果太寬鬆)才寫註解。
✅ 不用寫:簡單的變數賦值。
let age = 18; // TS 自動知道這是 number✅ 一定要寫:函式參數。
function printId(id: number) { ... }✅ 建議寫:函式回傳值(為了文件化和防止意外修改)。
function getUser(): User { ... }
Q: 如果我真的不知道是什麼型別怎麼辦?
如果你正在從 JavaScript 遷移過來,或者處理一些很動態的資料,你可以暫時使用 any,但請記住這是下下策。
// 盡量避免
let data: any = JSON.parse(response);
// 比較好的做法是定義一個大致的介面,或者用 unknown
let safeData: unknown = JSON.parse(response);