iT邦幫忙

2022 iThome 鐵人賽

DAY 8
1
自我挑戰組

你也對開始使用typescript感到無力嗎?我也是 - 30天初探typescript系列 第 8

第八天!Type Alias & Interface 型別別名與介面

  • 分享至 

  • xImage
  •  

昨天講完相對少用的特殊型別,讓我們再回到比較重要的部分。

我們在第五天時,有提到型別別名(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之中,越新的版本,差異已經越來越小了。你可以挑你習慣用的用法,只要在整個專案中,團隊有說好、並前後一致即可。

系列文到這個階段,對interfacetype不熟悉是再正常不過的了,我們後續一定會再來回顧的!
今天是週五,祝大家週末愉快!


上一篇
型別介紹part4 - 一些特殊的型別
下一篇
第九天! 選擇性屬性與唯讀屬性
系列文
你也對開始使用typescript感到無力嗎?我也是 - 30天初探typescript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言