昨天講完相對少用的特殊型別,讓我們再回到比較重要的部分。
我們在第五天時,有提到型別別名(Type Alias),這邊再複習一次:我們可以將特定組合的型別,給安上一個別名,方便我們後續使用,成為一個新的type(但不跳脫原生的javascript既有型別)。舉例來說,我們通常預期一個人Person
,會有字串的name
跟數字的age
,因此我們可以將這個組合拉出來使用:
type Person = {
name: string
age: number
}
function sayHi(person: Person) {
console.log(`Hi ${person.name}, you're ${person.age} year(s) old.`)
}
// 就不用一直在參數的地方重複寫,閱讀上也更有意義一些
function sayHi2(person: { name: string, age: number }) {
console.log(`Hi ${person.name}, you're ${person.age} year(s) old.`)
}
function sayHi3(person: { name: string, age: number }) {
// 略
}
而TypeScript當中,有一個跟型別別名長得很像的東西,叫做Interface(介面)。我們來看一下他的基本寫法:
interface Person {
name: string
age: number
}
看起來跟型別別名真的超像的。
但基本上,interface是用來形容資料的形狀的,像物件。所以這邊不能像type一樣直接指涉type sentence = string
,他不能拿來指涉聯集、原始值、或其他型別。
跟type最大的不同應該是這點:interface可以一直被擴充。
interface Noodle {
name: string
}
interface Noodle {
price: number
}
// 下面這句完全合法,不會報錯
const dish: Noodle = { name: "Beef noodles", price: 120 }
// 但如果是type,就會報錯:
// Duplicate identifier 'Rice'.
type Rice = {
name: string
}
type Rice = {
price: number
}
TypeScript會直接將同樣名稱的interface合而為一,不過前提是這當中沒有重複/衝突的屬性
interface Noodle {
name: string
}
interface Noodle {
// Subsequent property declarations must have the same type. Property 'name' must be of type 'string', but here has type 'number'.
name: number
}
// 有這種警告訊息真的很讚,有錯也能很快發現
若要更明確的"擴充"介面,則可以透過關鍵字extends
來擴充,我這邊直接拿官方文件的例子,比較省事一些:
interface Animal {
name: string
}
interface Bear extends Animal {
honey: boolean
}
// 這邊的Bear就從Animal擴充了honey屬性
const bear: Bear = {
honey: true,
name: "Winnie"
}
但如果type想要"擴充",其實也是可以的,只是寫法有些不同,必須透過交集(intersection)來實作,其實就是&
符號啦:
type Rice = {
name: string
}
type RiceWithPrice = Rice & {
price: number
}
let friedRice: RiceWithPrice = {
name: "Yangzhou fried rice", price: 140
}
甚至,我們可以混著使用型別別名與介面
interface Name {
name: string
};
interface Age {
age: number
};
type Person = Name & Age;
let guy: Person = {
name: "John",
age: 18
}
我知道寫到這邊,大家已經有點搞不清楚了,我們其實還有更多排列組合能嘗試(但說真的不要這樣做,太混亂了)。
到底什麼情況下用type
?什麼情況下用interface
?根據我爬了一些國外技術文章與youtuber的影片後,發現青菜蘿蔔各有所好,甚至有比較多的聲音是建議你直接使用interface
就好,因為兩者之間真的太相似了,他們之間的差異,大多只存在比較舊版的TypeScript之中,越新的版本,差異已經越來越小了。你可以挑你習慣用的用法,只要在整個專案中,團隊有說好、並前後一致即可。
系列文到這個階段,對interface
及type
不熟悉是再正常不過的了,我們後續一定會再來回顧的!
今天是週五,祝大家週末愉快!