跳到主要内容

Interfaces(介面)

通常一個 TypeScript 介面的宣告,就是要被作為:物件的規格。

介面擴展(Interface Extension / Inheritance)

若我們有一系列 TypeScript 介面 I1, I2 ... In,其中:所有的介面裡,不同的介面卻互相有重複的屬性名稱 —— 這種情形是可以接受的;然而,名稱相同之屬性,各自對應之型別不能互相衝突。

若滿足以上條件,並且宣告介面 IMain 為 I1, I2 ... In 的擴展:

interface IMain extends I1, I2, ... In {}

則 IMain 為所有 I1, I2, ... In 交集的結果。

介面 Interface V.S. 型別 Type

從剛剛我們得出的結論:介面可以進行延伸或擴展(Interface Extension),這裡就可以開始點出介面跟型別系統的主要差別。

介面(Interface)的意義

—— 跟規格的概念很像,可以擴充設計、組裝出更複雜的功能規格

型別(Type)的意義

—— 代表靜態的資料型態,因此型別一但被定義出來則恆為固定的狀態。儘管可以利用型態的複合(intersection 與 union)看似達到型別擴展的感覺,然而這個行為並不叫作型別擴展,而是創造出新的靜態型別

如果單純是原始型別或者是要表示為列舉型別、元組型別,一定只能使用 type 進行宣告

介面融合(Declaration Merging)

介面的函式超載 Function Overload

interface AddOperation {
addition(p1: number, p2: number): number;
addition(p1: string, p2: string): number;
}

const implementAddition: AddOperation = {
addition(p1: number | string, p2: number | string) {
// 型別限縮 ——又名型別檢測,也就是 Type Guard—— 由判斷敘述式進行型別限縮
if (typeof p1 === 'number' && typeof p2 === 'number') {
return p1 + p2;
} else if (typeof p1 === 'string' && typeof p2 === 'string') {
return parseInt(p1, 10) + parseInt(p2, 10);
}

// 應對p1: string; p2: number跳脫後的錯誤處理(never)
throw new Error(`
Parameter \`p1\` and \`p2\` should only accept both \`number\`
type or \`string\` type.
`);
}
};

另一種

interface ISummation {
(...args: number[]): number;
//有時候,Function 接受的參數數量不固定,而 其餘參數(Rest Operator) 的功能就是把多的參數併成一個 Array。
(arr: number[]): number;
}

let F: ISummation = function (p1: number | number[], ...args: number[]) {
if (
// Type Guard 實踐:確保 p1 是數字,arr 是數字型陣列
typeof p1 === 'number' &&
args instanceof Array
) {
// ...
// 將 p1 與 arr 裡面的值加總起來
return args.reduce((acc, cur) => acc + cur, p1);
} else if (
// Type Guard 實踐:確保 p1 是陣列
p1 instanceof Array
) {
// 因為 p1 被認為是陣列,因此加總起來
return p1.reduce((acc, cur) => acc + cur, 0);
}

// 滿足 `never` 的 Case
throw new Error(`Something is wrong with your input`);
};
// 使用 (...args: number[]): number 的方式:
F(1, 2, 3, 4, 5);
// 結果是 1 + 2 + 3 + 4 + 5 = 15

// 使用 (arr: number[]): number 的方式:
F([1, 2, 3, 4, 5]);
// 結果也是 1 + 2 + 3 + 4 + 5 = 15
// 裡面摻雜亂源會被發現錯誤
F(1, 2, '3', 4, 5);

// 陣列型別也是,裡面摻雜亂源會被發現錯誤
F([1, 2, '3', 4, 5]);

第三方套件或框架協作

“我們不可能在第三方套件或框架早已經定義的介面裡進行介面擴充的動作啊!那已經被寫死在該框架裡了,要是再被改,這個框架相依賴的其他套件不就也有壞掉的可能嗎?”

藉由介面融合的方式,和第三方套件或框架協作 —— 打造出屬於我們的 TS 專案適合的型別版本!

// 第三方套件的 Definition File:
namespace StupidFramework {
interface StupidRequest {
headers: Header[];
body: Body;
url: string;
method: 'GET' | 'POST' | ... | 'DELETE';
//query?: Dictionary; 直接加就等著以後GG
...
}
}

/* -------- 分隔線代表不同的檔案 -------- */

// 我們的專案自定義的狀態
type Dictionary = { [propName: string]: string };

namespace StupidFramework {
interface StupidRequest {
query?: Dictionary;
}
// }