昨天我們聊了陣列與 Tuple,今天來看看 TypeScript 裡另一個重量級角色——
物件型別。物件是專案裡最常出現的資料結構,如果不加規範,很容易就變成一坨「大家隨便塞」的混亂資料。
物件型別就是替物件的「形狀」立一份規範,告訴 TS 這個物件應該長什麼樣子。
let user: { name: string; age: number } = {
name: "Marco",
age: 25
};
如果你漏填或填錯型別,TS 會立刻抓到:
user = { name: "Alice" };
// ❌ Property 'age' is missing
當物件結構比較複雜時,最好用 type
或 interface
定義:
type User = {
name: string;
age: number;
};
let u: User = { name: "Bob", age: 30 };
兩者差別會在進階篇講(Day 9)。
有些欄位不是必填,可以加 ?
:
type User = {
name: string;
age?: number; // 可選
};
let u1: User = { name: "Alice" };
let u2: User = { name: "Bob", age: 20 };
防止屬性被修改:
type User = {
readonly id: string;
name: string;
};
let u: User = { id: "123", name: "Charlie" };
u.id = "456";
// ❌ Cannot assign to 'id' because it is a read-only property.
當屬性名稱不固定,但型別一致時:
type StringMap = {
[key: string]: string;
};
let colors: StringMap = {
red: "#ff0000",
green: "#00ff00"
};
限制數字 key:
type NumberMap = {
[key: number]: string;
};
物件型別可以互相嵌套:
type Address = {
city: string;
zipCode: string;
};
type User = {
name: string;
address: Address;
};
let u: User = {
name: "Diana",
address: {
city: "Taipei",
zipCode: "100"
}
};
假設後端回傳使用者資料:
type ApiResponse<T> = {
data: T;
status: number;
message: string;
};
type User = {
id: string;
name: string;
email: string;
};
let res: ApiResponse<User> = {
data: { id: "u001", name: "Marco", email: "marco@example.com" },
status: 200,
message: "OK"
};
這種結構化的型別讓 API 對接更安全。
TS 會檢查物件字面量的多餘屬性:
type User = { name: string };
let u: User = { name: "Alice", age: 20 };
// ❌ Object literal may only specify known properties
解法:先用變數接,或用型別斷言:
let tmp = { name: "Alice", age: 20 };
let u: User = tmp; // OK
as const
鎖定物件const CONFIG = {
API_URL: "https://api.example.com",
TIMEOUT: 5000
} as const;
// CONFIG.API_URL 型別是 "https://api.example.com"