TypeScript 泛型(Generics)详解及示例
1. 什么是泛型?
泛型是 TypeScript 中创建可重用组件的重要工具,它允许我们创建可以处理多种类型而不是单一类型的组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function identityNumber(arg: number): number { return arg; }
function identityString(arg: string): string { return arg; }
function identity<T>(arg: T): T { return arg; }
|
2. 基础泛型语法
泛型函数
1 2 3 4 5 6 7 8 9
| function identity<T>(arg: T): T { return arg; }
let output1 = identity<string>("hello"); let output2 = identity("world");
|
泛型接口
1 2 3 4 5 6 7 8
| interface GenericIdentityFn<T> { (arg: T): T; }
let myIdentity: GenericIdentityFn<number> = identity;
|
泛型类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T;
constructor(zeroValue: T, add: (x: T, y: T) => T) { this.zeroValue = zeroValue; this.add = add; } }
let numberInstance = new GenericNumber<number>(0, (x, y) => x + y);
let stringInstance = new GenericNumber<string>("", (x, y) => x + y);
|
3. 泛型约束
使用 extends 约束
1 2 3 4 5 6 7 8 9 10 11 12 13
| interface Lengthwise { length: number; }
function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; }
loggingIdentity("hello"); loggingIdentity([1, 2, 3]);
|
多类型约束
1 2 3 4 5 6 7 8 9 10 11 12 13
| function copyFields<T extends U, U>( target: T, source: U ): T { for (let id in source) { target[id] = (source as any)[id]; } return target; }
let x = { a: 1, b: 2, c: 3, d: 4 }; copyFields(x, { b: 10, d: 20 });
|
4. 泛型在类中的高级用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Stack<T> { private items: T[] = [];
push(item: T): void { this.items.push(item); }
pop(): T | undefined { return this.items.pop(); }
peek(): T | undefined { return this.items[this.items.length - 1]; }
size(): number { return this.items.length; } }
const numberStack = new Stack<number>(); numberStack.push(1); numberStack.push(2); console.log(numberStack.pop());
const stringStack = new Stack<string>(); stringStack.push("hello"); stringStack.push("world");
|
5. 泛型与接口结合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| interface KeyValuePair<K, V> { key: K; value: V; }
let pair1: KeyValuePair<number, string> = { key: 1, value: "one" }; let pair2: KeyValuePair<string, boolean> = { key: "isValid", value: true };
interface Transformer<T, U> { (input: T): U; }
const stringToNumber: Transformer<string, number> = (str) => parseInt(str); const numberToString: Transformer<number, string> = (num) => num.toString();
|
6. 条件类型与泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| type IsString<T> = T extends string ? true : false;
type A = IsString<string>; type B = IsString<number>;
type TypeName<T> = T extends string ? "string" : T extends number ? "number" : T extends boolean ? "boolean" : "object";
function getTypeName<T>(arg: T): TypeName<T> { return typeof arg as TypeName<T>; }
const result1 = getTypeName("hello"); const result2 = getTypeName(42);
|
7. 泛型工具类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| interface User { name: string; age: number; }
type PartialUser = Partial<User>;
type ReadonlyUser = Readonly<User>;
type UserName = Pick<User, "name">;
type PageInfo = Record<"home" | "about" | "contact", { title: string }>;
const pages: PageInfo = { home: { title: "首页" }, about: { title: "关于" }, contact: { title: "联系" } };
|
8. 实际应用示例
API 响应处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| interface ApiResponse<T> { success: boolean; data: T; message?: string; }
interface User { id: number; name: string; email: string; }
interface Product { id: number; title: string; price: number; }
async function fetchData<T>(url: string): Promise<ApiResponse<T>> { const response = await fetch(url); return response.json(); }
const userResponse = await fetchData<User>("/api/users/1"); const productResponse = await fetchData<Product>("/api/products/1");
|
数据处理工具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class DataProcessor<T> { private data: T[];
constructor(data: T[]) { this.data = data; }
filter(predicate: (item: T) => boolean): DataProcessor<T> { return new DataProcessor(this.data.filter(predicate)); }
map<U>(mapper: (item: T) => U): DataProcessor<U> { return new DataProcessor(this.data.map(mapper)); }
get(): T[] { return this.data; } }
const numbers = [1, 2, 3, 4, 5]; const result = new DataProcessor(numbers) .filter(n => n > 2) .map(n => n * 2) .get();
|
9. 泛型最佳实践
- 使用有意义的泛型参数名:
1 2 3
| function identity<Type>(arg: Type): Type { return arg; } function processData<Input, Output>(input: Input): Output { }
|
- 适当使用约束:
1 2 3 4
| function getProperty<T, K extends keyof T>(obj: T, key: K) { return obj[key]; }
|
- 避免过度使用泛型:只在真正需要灵活性时使用。
泛型大大增强了 TypeScript 的类型安全性和代码重用性,是现代 TypeScript 开发中的重要特性。