# 【TypeScript】extends vs. implements / type vs. interface
`20240213Tue.`
## 前言
這裡看了Udemy課程:[React & TypeScript - The Practical Guide](https://www.udemy.com/course/react-typescript-the-practical-guide/) 2-19,裡頭提到type跟interface的差異,但覺得老師講得稍微淺,所以有在上網找些資料,另外老師上課還提到了一個關鍵字"implements"(屬TS關鍵字),所以這裡會分成兩個部份比較以及綜合implements與interface介紹:
1. extends vs. implements
2. type vs. interface
3. 綜合:implements + interface
## 1. extends vs. implements
我們先建立一個玩家Player的class

```typescript!
class Player{
level = 1;
clothes = "white";
pants = "red";
shoes = "blue";
hair = "bald";
walkLeft(){};
walkRight(){};
}
```
* ### **extends**
現在,我們想建立一個初心者Beginner利用「extends」來繼承這個Player的屬性與功能,且讓Beginner只繼承Player外不再有任何新增修改的動作,最後再透過Beginner class來建立實例Jhon。
```typescript!
class Beginner extends Player{}
const Jhon = new Beginner;
```
這個時候若我們打Jhon,可以看到Jhon的確繼承了Player的所有屬性與功能,並且完全沒有報錯。

* ### **implements**
現在,改成利用「implements」,我們依上面用extends時相同的作法照做。
```typescript!
class Beginner implements Player{}
const Jhon = new Beginner;
```
會發現報錯了...

錯誤中提到level, clothes, pants, shoes及其他三個屬性或功能不見了!
這是因為如果使用implements的話,implements並不會去繼承父類,implements只會拿取父類的模板、範本、樣子(看要怎麼翻譯,英文是說pattern、shape),所以既然拿了父類的模板,當然就要都「實現」出來才對。
因此把上方程式碼修正一下,把父類該有的都加上,就不會報錯了。
```typescript!
class Beginner implements Player{
level = 1;
clothes = "white";
pants = "red";
shoes = "blue";
hair = "bald";
walkLeft(){};
walkRight(){};
}
const Jhon = new Beginner;
```
* ### **總結**

## 2. type vs. interface
### ▎直接擴充(或者說同名融合)
先看看官方文件怎麼說?
> Type aliases and interfaces are very similar, and in many cases you can choose between them freely. Almost all features of an interface are available in type, the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.
官方說基本上type與interface兩者非常相似,我們在許多情況下其實都可以很自由地選擇要使用type或interface。而其中最關鍵的差異在於type沒辦法直接增加新屬性,而interface則可以隨時去擴展、添加新屬性。
* ### **type**
沒辦法直接添加新屬性,若想用同名的type去增加新屬性會報錯"Duplicate identifier 'Human'"。
```typescript!
type Human = {
age: number
}
//報錯:Duplicate identifier 'Human'
type Human = {
name: string
}
```
* ### **interface**
可以直接添加新屬性,用同名的interface增加新屬性會合併起來。
```typescript!
interface Human{
age: number
}
interface Human{
name: string
}
let Player1: Human;
Player1 = {
age: 20,
name: "Amy"
}
```
老師在課堂中有提到,為什麼會有同名的interface出現的問題,為什麼不合寫在同一個interface就好?因為有可能一個開發者先開發了一個基本的library供其他開發者使用,而其他開發者拿了這個library發現好像還可以再新增一些酷東西,但不希望直接改到原本library的內容,於是就可以利用同名的interface做擴展的動作。
### ▎透過其他方式擴充
雖然說前面看到type沒辦法直接擴展,但其實有別的辦法作到「類似」擴展的效果,因為事實上type做擴展是把舊有的型別做擴展後,另外assign給新的型別別名(type alias),不像interface可以直接繼承:
1. type可以透過"&"「類似」擴展
2. interface可以透過"extends"繼承方式擴展
* ### **type**
type可以透過"&"擴展,這裡以形狀來舉例,我們針對Shape物件型別定義其有area屬性,且area型別為number,接著透過"&"去擴展Shape型別。

```typescript!
//定義Shape型別
type Shape = {
area: number;
}
//透過"&"擴展Shape型別
//不過與其說擴展,更像是另外定義新的型別
type Circle = Shape & {
radius: number;
}
type Square = Shape & {
width: number;
}
type Rectangle = Shape & Square & {
height: number
}
```
這個時候我們就可以來使用這些自定義的型別名稱了。
```typescript!
const circle: Circle = {
area: 314,
radius: 10
}
const square: Square = {
area: 100,
width: 10
}
const rectangle: Rectangle = {
area: 500,
width: 20,
height: 25
}
```
* ### **interface**
interface可以透過"extends"繼承方式擴展。
```typescript!
interface Shape{
area: number;
}
interface Circle extends Shape{
radius: number;
}
interface Square extends Shape{
width: number;
}
interface Rectangle extends Shape, Square{
height: number
}
```
使用上面定義好的型別。
```typescript!
const circle: Circle = {
area: 314,
radius: 10
}
const square: Square = {
area: 100,
width: 10
}
const rectangle: Rectangle = {
area: 500,
width: 20,
height: 25
}
```
## 3. 綜合:implement + interface
綜合以上內容,就可以來看看怎麼把interface與implement合在一起使用。
首先,我們先針對驗證物件定義好一個型別。
```typescript!
interface Credentials{
email: string,
password: string
}
```
現在,我要創建一個User class,且希望可以利用到剛剛定義好的Credentials型別,這個時候利用"implements"關鍵字,代表說我要拿取父類的模板來用,所以父類的模板長怎樣,我子類的class中就必須都要擁有。
```typescript!
interface Credentials{
email: string,
password: string
}
class User implements Credentials{
email: string;
password: string;
nickname: string
}
let Amy = new User();
Amy = {
email: "abc@gmail.com",
password: "abc",
nickname: "Amyyyyy"
}
```
## 參考資料:
* [TypeScript Implements vs. Extends Explained](https://www.youtube.com/watch?v=ld4QMSgfAXc)
* [换个角度理解 Typescript 的 type 和 interface](https://zhuanlan.zhihu.com/p/351213183)
* [TypeScript官方文件:Differences Between Type Aliases and Interfaces](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces)
* [Day 16. 機動藍圖・介面與型別 X 混用與比較 - TypeScript Interface V.S. Type](https://ithelp.ithome.com.tw/articles/10216626)
* [[TS] Interfaces](https://pjchender.dev/typescript/ts-interface/#%E6%96%B9%E6%B3%95%E4%BA%8C%E4%BD%BF%E7%94%A8-index-signature-%E4%BE%86%E9%81%BF%E5%85%8D-excess-property-checking)