2022.10.08 更新
這天誤用type casting一詞,今天緊急刪掉這個主題,因為嚴格來說TypeScript沒有type casting,詳情可見這部影片或這篇stackoverflow的內容。
TypeScript Turtorial看到目前為止差不多要結束了,快沒題材可以繼續發文XD
不過在彙整TypeScript關鍵字(keyword)和運算子(operator)的時候,發現有幾個可以一起討論的有趣主題(而且應該能讓我發個四、五天左右的文),這些主題分別是:
要先知道這幾個主題,才比較好了解TypeScript的關鍵字和運算子在做什麼,那麼今天先從第10天也有提到、比較好了解的Type Alias開始說起。
某些時候TypeScript內建型別不符所需,開發者可能會自行建立一些較複雜的型別。
為了可以重複利用自己建立的複雜型別,TypeScript允許開發者替型別額外取名字,而這些型別額外取的名字就稱為 Type Alias。
替型別取別名的方式類似於替變數命名,以 type
關鍵字開頭,空格後加上型別別名和 =
,接著才是自行建立的型別,例如:
type MyType = string | number | boolean;
如此一來 MyType
就可以在檔案中任何地方使用,甚至如果熟悉JavaScript的模組輸入輸出方式,也能將 MyType
輸出,並且讓需要的檔案引入。
例如我在專案中特地建立一個共用型別的檔案 types.ts
,裡面放置多個檔案會用到的型別:
// types.ts
export type Code = string | number;
export type ...
然後可以在需要的檔案引入:
// any-file.ts
import { Code } from 'types.ts';
let myCode: Code;
myCode = "1010"; // ok
myCode = 1010; // ok
myCode = false; // error
type
關鍵字可以替任何型別命名,所以也可以替一個物件(object)型別取個有意義的名稱,提高程式碼可讀性:
type Position = {
x: number;
y: number;
z: number;
}
function Draw(pos: Position){
console.log(`draw (${pos.x}, ${pos.y}, ${pos.z}`));
}
Draw({x: 0, y: 100, z: 100}); // draw (0, 100, 100)
看到這裡可能會想說:嘿!這跟第16天用 interface
定義物件的方式有什麼不同?
先回顧一下之前說過的TypeScript型別系統 - Structural Type System,這種系統允許變數型別的 外型(shape) 大致符合,就能說這個變數就是我要的了,譬如我們讓另一個物件輸入Draw函式:
type Position = {
x: number;
y: number;
z: number;
}
function Draw(pos: Position){
console.log(`draw (${pos.x}, ${pos.y}, ${pos.z}`));
}
Draw({x: 0, y: 100, z: 100, k: -5}); // draw (0, 100, 100), k沒有被使用
如果單純從定義物件 外型(shape) 的角度看待 type 和 interface ,事實上,這兩個關鍵字的作用幾乎是一樣的,甚至可以互相延展(extends)!?譬如 type & interface
或是 interface XXX extends type
。
若要說 type 和 interface 有什麼不一樣,大致會有以下幾點不同之處:
&
運算子,interface 用 extends
;以下舉例第1點和第3點:
// 1.
type Position = {
x: number;
y: number;
z: number;
}
interface Location {
lat: number;
lng: number;
}
// type "intersects" interface
type Place = Location & {
name: string;
address: string;
}
// interface "extends" type
interace Shape extends Position {
width: number;
length: number;
};
// ============================================= //
// 3.
Position = { a: number; b: number; } // error
interface Location { // ok
x: number;
y: number;
}
也就是說,兩者若是用在宣告一個物件的樣態時,除了以上幾點,幾乎是一樣的。
不過 type 和 interface 各自還有其他用途,譬如:
union
型別, interface 不行;class
實作(implements),但 type 不行。若是從這幾點來看,用 type 和 interface 宣告物件的主要目的仍然是不一樣的,因此開發時還是要考慮一下使用這兩者宣告物件的用途。
參考資料
Type Aliases @TypeScript Handbook
Differences Between Type Aliases and Interfaces @TypeScript Handbook
interface vs type @TS Playground
TypeScript Type Aliases @TypeScript Tutorial
Interfaces vs Types in TypeScript @stackoverflow