TypeScript 泛型
方法簽名解析
private repeatArrayToLength<T>(arr: T[], targetLength: number): T[]
泛型 <T>
詳細說明
<T>
詳細說明什麼是泛型?
泛型 (Generics) 是 TypeScript 的一個強大特性,允許我們編寫可重複使用的程式碼,同時保持型別安全。
<T>
的含義
<T> // T 是一個型別變數 (Type Variable)
T 代表 "Type",是一個佔位符
可以用任何名稱,如
<U>
、<K>
、<V>
,但<T>
是慣例在方法被呼叫時,T 會被具體的型別取代
泛型的運作原理
// 方法定義
private repeatArrayToLength<T>(arr: T[], targetLength: number): T[]
// 呼叫時,TypeScript 會推斷或明確指定 T 的型別
使用範例與型別推斷
範例 1:字串陣列
const colors = ['red', 'blue', 'green'];
const repeatedColors = this.repeatArrayToLength(colors, 5);
// TypeScript 推斷:
// T = string
// arr: string[]
// 返回值: string[]
// repeatedColors = ['red', 'blue', 'green', 'red', 'blue']
範例 2:數字陣列
const numbers = [1, 2, 3];
const repeatedNumbers = this.repeatArrayToLength(numbers, 7);
// TypeScript 推斷:
// T = number
// arr: number[]
// 返回值: number[]
// repeatedNumbers = [1, 2, 3, 1, 2, 3, 1]
範例 3:物件陣列
interface Color {
name: string;
hex: string;
}
const colorObjects: Color[] = [
{ name: 'red', hex: '#FF0000' },
{ name: 'blue', hex: '#0000FF' }
];
const repeatedColorObjects = this.repeatArrayToLength(colorObjects, 3);
// TypeScript 推斷:
// T = Color
// arr: Color[]
// 返回值: Color[]
// repeatedColorObjects = [
// { name: 'red', hex: '#FF0000' },
// { name: 'blue', hex: '#0000FF' },
// { name: 'red', hex: '#FF0000' }
// ]
範例 4:明確指定型別
// 雖然不常見,但可以明確指定型別
const result = this.repeatArrayToLength<string>(['a', 'b'], 4);
// 明確告訴 TypeScript:T = string
沒有泛型的版本對比
不使用泛型(型別不安全)
// ❌ 不好的寫法
private repeatArrayToLength(arr: any[], targetLength: number): any[] {
// ...
}
// 問題:失去型別安全性
const colors = ['red', 'blue'];
const result = this.repeatArrayToLength(colors, 3);
// result 的型別是 any[],無法享受 TypeScript 的型別檢查
使用泛型(型別安全)
// ✅ 好的寫法
private repeatArrayToLength<T>(arr: T[], targetLength: number): T[] {
// ...
}
// 優點:保持型別安全性
const colors = ['red', 'blue'];
const result = this.repeatArrayToLength(colors, 3);
// result 的型別是 string[],享受完整的型別檢查和智能提示
Array.from 詳解
基本語法
Array.from(arrayLike, mapFunction?, thisArg?)
在我們方法中的使用
return Array.from(
{ length: targetLength }, // arrayLike: 類陣列物件
(_, index) => arr[index % arr.length] // mapFunction: 映射函數
);
分解說明
1. 建立類陣列物件
{ length: targetLength }
// 例如 targetLength = 5 時
// { length: 5 }
// 這會被 Array.from 視為有 5 個元素的類陣列
2. 映射函數
(_, index) => arr[index % arr.length]
// 參數說明:
// _: 當前元素值(我們不需要,所以用 _ 表示忽略)
// index: 當前索引 (0, 1, 2, 3, 4...)
// 範例:arr = ['red', 'blue', 'green'], targetLength = 7
// index = 0: arr[0 % 3] = arr[0] = 'red'
// index = 1: arr[1 % 3] = arr[1] = 'blue'
// index = 2: arr[2 % 3] = arr[2] = 'green'
// index = 3: arr[3 % 3] = arr[0] = 'red' ← 循環開始
// index = 4: arr[4 % 3] = arr[1] = 'blue'
// index = 5: arr[5 % 3] = arr[2] = 'green'
// index = 6: arr[6 % 3] = arr[0] = 'red'
// 結果: ['red', 'blue', 'green', 'red', 'blue', 'green', 'red']
模運算 (%) 的循環邏輯
// 模運算的循環特性
arr.length = 3
index % arr.length 的結果:
0 % 3 = 0 → arr[0]
1 % 3 = 1 → arr[1]
2 % 3 = 2 → arr[2]
3 % 3 = 0 → arr[0] ← 重新開始
4 % 3 = 1 → arr[1]
5 % 3 = 2 → arr[2]
6 % 3 = 0 → arr[0] ← 再次循環
完整執行流程示範
// 呼叫範例
const colors = ['red', 'blue', 'green'];
const result = this.repeatArrayToLength(colors, 5);
// 執行步驟:
// 1. T 被推斷為 string
// 2. 邊界檢查:arr.length = 3 > 0, targetLength = 5 > 0 ✓
// 3. Array.from 執行:
// { length: 5 } 建立 5 個位置的類陣列
// index = 0: colors[0 % 3] = colors[0] = 'red'
// index = 1: colors[1 % 3] = colors[1] = 'blue'
// index = 2: colors[2 % 3] = colors[2] = 'green'
// index = 3: colors[3 % 3] = colors[0] = 'red'
// index = 4: colors[4 % 3] = colors[1] = 'blue'
// 4. 返回:['red', 'blue', 'green', 'red', 'blue']
Last updated