TypeScript 陣列與元組 (Array and Tuple)

在 JavaScript 中,陣列 (Array) 可以放任何東西,這雖然方便,但也是很多 bug 的來源。TypeScript 把它細分為兩種概念:陣列元組

陣列 (Array)

這是最常見的情況:一個長度不固定的清單,而且裡面裝的東西通常是同類型的

宣告方式

這兩行是一模一樣的,挑你喜歡的寫就好 (通常第一種比較常見)。

let list1: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3];

如果你想宣告一個「裡面什麼都能放」的陣列:

// 雖然可以,但盡量不要用 any
let list: any[] = [1, true, 'hello'];

元組 (Tuple)

這是 TypeScript 特有的概念。

當你明確知道這個陣列:

  1. 長度是固定的
  2. 每個位置的型別也是固定的

這時候就應該用元組。

// 定義:只能有兩個元素,第一個是 string,第二個是 number
let x: [string, number];

x = ['hello', 10]; // OK
// x = [10, "hello"]; // 錯誤:順序不對

實際應用:React useState

你一定用過或看過 React 的 Hook:

const [count, setCount] = useState(0);

這就是一個典型的元組應用!

  • 第一個位置一定是狀態值 (count)
  • 第二個位置一定是設定函式 (setCount)

如果 useState 回傳的是普通陣列 ((number | Function)[]),那你使用時就麻煩了,因為 TS 不知道第一個元素到底是數字還是函式。

但因為它回傳的是 [number, Dispatch<SetStateAction<number>>] (元組),TS 可以精確地知道 count 就是數字,可以直接做數學運算。

唯讀陣列 (Readonly Array)

如果你希望陣列宣告後就不能被修改 (Immutable),可以使用 readonly

const ro: readonly number[] = [1, 2, 3, 4];

// ro.push(5);      // 錯誤!唯讀陣列沒有 push 方法
// ro[0] = 12;      // 錯誤!無法修改元素

這在 Redux 或任何強調不可變性的架構中非常有用,它能防止你意外地修改了原始資料。

總結

名稱特徵範例
陣列長度可變,型別通常相同number[] ([1, 2, 3, 4...])
元組長度固定,位置對應型別[string, number] (["Age", 18])