介面
提供給軟體元件間的介面會被存取到的事物的種類可以包括:常數資料型別程式的種類、例外規格、型別簽名。在某些個案,定義變數作為介面的一部份可能會很有用。介面常會透過註解或(於某些實驗性語言)透過正式的邏輯斷言指明那些程式和方法的功能。
-- wikipedia
如果你是一名使用過物件導向語言做開發的開發者,肯定對 Interface 不陌生。
Interface 可以讓我們先對物件規定好範疇,再進行實作。
以 PHP 為例,若我們今天想要實作一個 Linked List :
1
interface linkedListInterface{
2
function printList();
3
function pushFront($data);
4
function delete($inputValue);
5
function pushBack($data);
6
function reverse();
7
function clearList();
8
}
9
class linkedList implements linkedListInterface{
10
// 實作...
11
}
Copied!
上述程式碼中,我們先定義好了一個資料結構中有的抽象方法,再使用 class 進行實作。
或許有人會覺得先定義好再做實作很多此一舉,但是當今天有多人開發的需求, Interface 就是一個相當好用的工具,因為先定義好了相關屬性和方法,可以有效避免多人開發的衝突。

介面實戰

而在 TypeScript 中,我們同樣可以介面來定義物件的型別,至於到底該如何使用介面,就讓我們一起看看以下範例吧!
每個人都有姓名跟年齡, ian 也是人,所以在用物件定義 ian 之前,我們可以把這些確定的事物給抽離出來:
1
interface Person {
2
name: string;
3
age: number;
4
}
Copied!
定義好一個人必備的元素後,實作物件 ian 時,我們就可以遵尋定義好的介面 Person
1
let ian: Person = {
2
name: 'Ian',
3
age: 21
4
};
Copied!
需要注意的是,在遵循介面實作物件時,不能有多餘或是缺少的屬性,像是:
1
let ian: Person = {
2
name: 'Ian',
3
age: 21,
4
birthday: 19990119
5
};
Copied!
或是:
1
let ian: Person = {
2
name: 'Ian',
3
};
Copied!
如果讀者認為某些屬性就算沒有被實作出來也沒關係,也可以考慮使用可選屬性: ?
1
interface Person {
2
name: string;
3
age?: number;
4
}
Copied!
如此一來,不實作 age 也沒關係啦!
1
let peter: Person = {
2
name: 'Peter',
3
};
Copied!
假設讀者們更難搞,希望實作物件時可以有預期之外的屬性出現,那我們可以使用任意屬性
1
interface Person {
2
name: string;
3
age?: number;
4
[propName: string]: string;
5
}
Copied!
注意,若定義了任意屬性,那麼確定屬性和可選屬性的型別都必須是它的型別的子集。
什麼意思呢?
我們透過歸類可以知道:
  1. 1.
    name 的型別是 string
  2. 2.
    age 的型別是 number
所以,任意屬性的型別至少必須是 stringnumber 的聯集:
1
interface Person {
2
name: string;
3
age?: number;
4
[propName: string]: string | number;
5
}
Copied!
更懶一點的作法,可以讓任意屬性的型別指定為 any
不過筆者不建議這麼做就是了。
1
interface Person {
2
name: string;
3
age?: number;
4
[propName: string]: string | number;
5
}
Copied!

補充:唯讀屬性

若今天讀者在實作物件時,希望該物件的特定屬性在物件初始化以後就不能重新進行賦值,可以使用唯獨屬性: readonly
1
interface Person {
2
readonly name: string;
3
age?: number;
4
[propName: string]: string | number;
5
}
Copied!
不過在現實世界中這樣做的話,應該會有人感到痛不欲生吧,像是:
而最好的作法應該是這樣:
1
interface Female {
2
name: string;
3
readonly age?: number;
4
}
5
let cindy: Female = {
6
name: 'Cindy',
7
age: 18
8
};
Copied!

延伸閱讀

同樣的事情在不同人眼中可能會有不同的見解、看法。
在讀完本篇以後,筆者也強烈建議大家去看看以下文章,或許會對型別、變數宣告...等觀念有更深層的看法唷!
Last modified 1yr ago