TypeScript 陣列型別宣告:string[] vs Array<string>
簡介
在 TypeScript 中,陣列(Array)是最常用的集合型別,幾乎每個專案都會與之打交道。正確且一致的型別宣告不只是提升程式碼可讀性,更能讓編譯器在開發階段即捕捉到潛在的錯誤。
本單元聚焦於兩種等價的寫法——string[] 與 Array<string>——說明它們的語法差異、使用情境與最佳實踐,幫助你在日常開發中做出最合適的選擇。
核心概念
1. 基本語法比較
| 寫法 | 語法說明 |
|---|---|
string[] |
使用後置的 [] 來表示「此型別的陣列」 |
Array<string> |
使用泛型 Array<T>,將元素型別作為參數傳入 |
兩者在編譯結果上完全等價,TypeScript 會把它們都映射成 Array<string>。差別僅在於 可讀性 與 與其他泛型結構的統一性。
// 兩種寫法皆可
let a: string[] = ["apple", "banana"];
let b: Array<string> = ["cat", "dog"];
小技巧:若你已經在使用其他泛型(例如
Promise<T>、Map<K, V>),使用Array<T>能讓整段程式碼的風格更一致。
2. 多維陣列的寫法
多維陣列在 [] 與泛型寫法上會產生明顯差異,這也是選擇其中一種寫法的關鍵時機。
// 使用 [] 寫法
let matrix1: number[][] = [
[1, 2],
[3, 4],
];
// 使用泛型寫法
let matrix2: Array<Array<number>> = [
[5, 6],
[7, 8],
];
number[][]看起來較為簡潔,但在深層嵌套時容易產生視覺混亂。Array<Array<number>>雖然較長,但在閱讀時可以清楚辨識每一層的「陣列」概念,對於 高階型別(如Array<Array<Array<string>>>)更具可讀性。
3. 與其他泛型結構的協同
當你同時使用 Map、Set、Promise 等泛型時,保持同一風格會讓程式碼更一致。
type User = { id: number; name: string };
// 使用 [] 風格
let userNames: string[] = [];
let userMap: Map<number, User> = new Map();
// 使用泛型風格
let userNames2: Array<string> = [];
let userMap2: Map<number, User> = new Map();
建議:在大型專案中,若團隊已決定以「泛型」為主(
Array<T>、Promise<T>),就盡量遵守此規範;若偏好簡潔的[],則全專案統一使用[]。
4. 型別推斷與 readonly 陣列
TypeScript 能根據初始值自動推斷陣列型別,這時兩種寫法的差別仍然不大。但在 只讀(readonly) 陣列上,語法稍有不同:
// 使用 [] + readonly
const readonlyNames: readonly string[] = ["Alice", "Bob"];
// 使用泛型 + ReadonlyArray
const readonlyNames2: ReadonlyArray<string> = ["Charlie", "Dave"];
readonly 前綴只能與 [] 搭配,而 ReadonlyArray<T> 則是 內建泛型別名。若你需要 只讀 陣列,建議直接使用 ReadonlyArray<T>,這樣可以與 Array<T> 保持同一風格。
5. 範例彙總(5 個實用範例)
範例 1:基本宣告與迭代
// string[] 版
let fruits: string[] = ["apple", "orange", "pear"];
fruits.forEach(f => console.log(`水果: ${f}`));
// Array<string> 版
let vegetables: Array<string> = ["carrot", "broccoli"];
vegetables.map(v => v.toUpperCase()).forEach(v => console.log(`蔬菜: ${v}`));
範例 2:函式參數與回傳值
// 接收 string[] 的函式
function joinWords(words: string[]): string {
return words.join(" ");
}
// 接收 Array<string> 的函式
function filterLongWords(words: Array<string>, minLen: number): Array<string> {
return words.filter(w => w.length >= minLen);
}
範例 3:多維陣列與型別別名
type Matrix = number[][]; // 使用 [] 風格
type Matrix2 = Array<Array<number>>; // 使用泛型風格
let m1: Matrix = [[1, 2], [3, 4]];
let m2: Matrix2 = [[5, 6], [7, 8]];
範例 4:只讀陣列
// 只讀陣列 (readonly + [])
const colors: readonly string[] = ["red", "green", "blue"];
// 只讀陣列 (ReadonlyArray)
const colors2: ReadonlyArray<string> = ["cyan", "magenta", "yellow"];
範例 5:與其他泛型結合
type ApiResponse<T> = Promise<Array<T>>;
// 取得字串陣列的 API
async function fetchUsernames(): ApiResponse<string> {
const data = await fetch("/api/users").then(r => r.json());
return data.names; // 假設回傳 { names: string[] }
}
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
| 混用兩種寫法 | 在同一檔案或同一介面中同時使用 string[] 與 Array<string>,會讓閱讀者感到混亂。 |
統一風格:在專案的 lint 規則(如 ESLint @typescript-eslint/array-type)中設定 default 為 array 或 generic。 |
| 錯把泛型當作函式 | Array<string>() 會被誤認為是呼叫 Array 建構子,實際上會產生 空陣列,而非型別宣告。 |
僅用於型別位置:Array<string> 只能寫在型別註解或泛型參數,不能直接作為值使用。 |
| 只讀與可變混用 | readonly string[] 與 Array<string> 同時出現在同一資料結構,可能導致意外的變更。 |
使用 ReadonlyArray<T> 或在介面中明確標註 readonly,保持一致性。 |
| 多維陣列的可讀性 | string[][][] 會讓人難以辨識層級。 |
改用 Array<Array<Array<string>>>,或建立型別別名 type TripleStringArray = Array<Array<Array<string>>>; |
推薦的 ESLint 設定
{
"rules": {
"@typescript-eslint/array-type": [
"error",
{
"default": "array", // 使用 string[]
"readonly": "generic" // 只讀陣列使用 ReadonlyArray<T>
}
]
}
}
小提醒:若團隊偏好
Array<T>,只要把"default": "generic"即可。
實際應用場景
API 回傳資料
多數 REST API 會回傳 JSON 陣列,例如string[]。在型別定義上,使用Array<string>可以直接與其他泛型(如Promise<T>)結合,寫出Promise<Array<string>>,保持語法一致。React/Angular 狀態管理
當使用useState<string[]>([])或this.items: Array<Item> = []時,兩者皆可。若你在同一個 component 中同時使用Map<string, number>、Set<number>,建議統一採用 泛型寫法,讓程式碼風格更整齊。函式庫設計
若你在發佈 npm 套件,對外介面最好使用Array<T>,因為它更能與其他泛型類型(如Observable<T>)自然結合,使用者在閱讀文件時也較不會混淆。多維資料結構(表格、棋盤)
在處理 2D/3D 表格或棋盤時,Array<Array<number>>的寫法比number[][]更直觀,尤其當你需要把「陣列」這個概念抽象化成型別別名時。
總結
string[]與Array<string>功能等價,差別僅在語法表達與團隊風格。- 多維陣列、只讀陣列以及與其他泛型結合時,泛型寫法 (
Array<T>) 更具可讀性與一致性。 - 為避免混亂,建議在 專案層面設定統一的 ESLint 規則,讓所有開發者遵守同一風格。
- 在實務上,根據 API 回傳、框架狀態管理或函式庫設計 的需求選擇最合適的寫法,才能在 TypeScript 中發揮型別系統的最大效益。
掌握這兩種陣列型別的差異與最佳實踐,你就能寫出 更安全、更易讀、且維護成本低 的 TypeScript 程式碼。祝開發順利!