TypeScript 泛型深度解析:從基礎到高級應用
作者:前端小石匠
泛型是 TypeScript 最閃耀的特性之一,它如同代碼世界的"萬能模具",讓開發者能夠鑄造出靈活且類型安全的組件。本文將帶您深入探索泛型的核心機制,并通過真實場景案例揭示其強大威力。
泛型是 TypeScript 最閃耀的特性之一,它如同代碼世界的"萬能模具",讓開發者能夠鑄造出靈活且類型安全的組件。本文將帶您深入探索泛型的核心機制,并通過真實場景案例揭示其強大威力。
一、泛型基礎:類型世界的變形金剛
1.1 為何需要泛型?
在傳統類型系統中,我們經常要為不同數據類型編寫重復代碼。比如處理數字和字符串的 identity 函數:
// 重復勞動示例
function identityNumber(arg: number): number {
return arg;
}
function identityString(arg: string): string {
return arg;
}
泛型的出現完美解決了這種冗余,它允許我們創建可適應多種類型的代碼模板[^1]。
1.2 泛型函數實現
function identity<T>(arg: T): T {
return arg;
}
// 自動類型推斷
const strOutput = identity('TS'); // string 類型
const numOutput = identity(2024); // number 類型
二、泛型應用場景全解析
泛型
2.1 集合操作:類型安全的容器
// 泛型數組處理
function reverseArray<T>(items: T[]): T[] {
return [...items].reverse();
}
const numbers = reverseArray([1, 2, 3]); // number[]
const letters = reverseArray(['a', 'b']); // string[]
2.2 數據建模:通用接口設計
// 通用響應接口
interface ApiResponse<T> {
status: number;
data: T;
timestamp: Date;
}
// 用戶數據響應
const userResponse: ApiResponse<User> = {
status: 200,
data: { id: 1, name: 'Alice' },
timestamp: new Date(),
};
// 產品列表響應
const productResponse: ApiResponse<Product[]> = {
status: 200,
data: [{ id: 1001, price: 99 }],
timestamp: new Date(),
};
2.3 類庫開發:可復用的組件
// 通用存儲器
class GenericStorage<T> {
private items: T[] = [];
addItem(item: T): void {
this.items.push(item);
}
getLatest(): T | undefined {
return this.items.slice(-1)[0];
}
}
// 使用示例
const numberStorage = new GenericStorage<number>();
numberStorage.addItem(42);
console.log(numberStorage.getLatest()); // 42
const userStorage = new GenericStorage<User>();
userStorage.addItem({ id: 2, name: 'Bob' });
三、高級泛型技巧
3.1 類型約束:給泛型戴上手銬
// 確保類型具有length屬性
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): void {
console.log(arg.length);
}
logLength('Hello'); // 5
logLength([1, 2, 3]); // 3
// logLength(2024); // 錯誤:number沒有length屬性
3.2 多重類型參數
// 元組生成器
function createPair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
const boolStrPair = createPair(true, 'yes'); // [boolean, string]
const numDatePair = createPair(10, new Date()); // [number, Date]
3.3 默認類型參數
// 帶默認值的泛型
interface Pagination<T = string> {
current: number;
pageSize: number;
data: T[];
}
const stringPagination: Pagination = {
current: 1,
pageSize: 10,
data: ['item1', 'item2'],
};
const numberPagination: Pagination<number> = {
current: 2,
pageSize: 20,
data: [1, 2, 3],
};
四、實戰應用案例
4.1 表單驗證器
interface Validator<T> {
isValid(value: T): boolean;
}
// 數字范圍驗證
class NumberRangeValidator implements Validator<number> {
constructor(private min: number, private max: number) {}
isValid(value: number): boolean {
return value >= this.min && value <= this.max;
}
}
// 郵箱格式驗證
class EmailValidator implements Validator<string> {
private regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
isValid(value: string): boolean {
return this.regex.test(value);
}
}
4.2 API 請求封裝
async function fetchData<T>(url: string): Promise<T> {
const response = await fetch(url);
if (!response.ok) throw new Error('Request failed');
return response.json();
}
// 使用示例
interface UserData {
id: number;
name: string;
}
const loadUser = async (userId: number) => {
try {
const user = await fetchData<UserData>(`/api/users/${userId}`);
console.log(user.name);
} catch (error) {
console.error('加載用戶失敗:', error);
}
};
五、最佳實踐與陷阱規避
推薦做法:
- 優先使用自動類型推斷
- 為復雜泛型添加類型注釋
- 合理使用泛型約束保證安全
常見錯誤:
- 過度使用 any 類型
- 忽略類型參數約束
- 創建過于復雜的泛型結構
六、未來展望:泛型的進階之路
隨著 TypeScript 的持續發展,泛型應用正在向更高級的領域延伸:
- 條件類型:實現類型層面的條件判斷
- 映射類型:批量轉換類型結構
- 類型體操:構建復雜的類型系統
// 條件類型示例
type NonNullable<T> = T extends null | undefined ? never : T;
type ValidString = NonNullable<string | null>; // string
責任編輯:武曉燕
來源:
前端小石匠