Interface 與 Type
真實專案裡的資料幾乎都是物件:API 回傳的 JSON、元件的 props、表單資料。interface 與 type 都是用來描述「這個物件長什麼樣子」的工具。
interface:描述物件形狀
interface User {
id: number
name: string
email?: string // 可選屬性
readonly createdAt: Date // 建立後不能再被賦值
}
function printUser(user: User) {
console.log(`${user.id}: ${user.name}`)
}
printUser({ id: 1, name: "Alice", createdAt: new Date() })
不需要 class 就能拿 interface 檢查一個一般物件字面值(object literal)符不符合形狀,這是 TypeScript 最日常的用法之一。? 是可選屬性,readonly 表示指定初值後不能再改。
type:型別別名
type Point = { x: number; y: number }
type ID = string | number // type 可以描述聯合型別,interface 不行
const origin: Point = { x: 0, y: 0 }
type 能做 interface 做不到的事:幫 union、tuple、函式型別、甚至基本型別取一個別名。上面 基本型別 提到的 Status 字面值聯合型別,就只能用 type 寫。
interface 還是 type?
兩者能力有很大一部分重疊,描述一般物件形狀時大多可以互換:
| 情境 | 建議 |
|---|---|
| 描述物件/class 的公開介面 | interface——之後要擴充時可以用 interface Foo { ... } 重複宣告來合併欄位 |
| 需要 union、tuple、函式型別、對基本型別取別名 | 只能用 type |
| 沒有特別偏好 | 選一種在專案裡保持一致就好,不必兩種混著用 |
官方 Handbook 的建議是:能用 interface 就先用 interface,遇到 interface 做不到的情況(例如 union)再用 type。
巢狀物件與陣列
interface Order {
id: number
items: { name: string; price: number }[]
customer: User // 直接複用前面定義的 interface
}
型別可以互相組合:物件裡的屬性可以是另一個 interface,也可以是物件陣列。這種組合方式最後會建立到 類別 與 泛型。
相關影音
Traversy Media 這支涵蓋 interface 與型別別名的實際用法,可搭配本頁範例一起看。