泛型
泛型是 TypeScript 中非常重要的特性,它允许我们在定义函数、接口或类时,不预先指定具体的类型,而在使用时再指定类型的一种特性。
为什么需要泛型?
- 类型复用:避免重复编写多个类型相似的函数
- 类型安全:在编译时进行类型检查,保证类型安全
- 灵活性:增强代码的可复用性和通用性
基础用法
1. 泛型函数
typescript
// 不使用泛型
function identity1(arg: number): number {
return arg;
}
// 使用泛型
function identity2<T>(arg: T): T {
return arg;
}
// 使用示例
const num = identity2<number>(123); // 明确指定类型
const str = identity2("hello"); // 类型推断
2. 泛型接口
typescript
interface GenericIdentity<T> {
(arg: T): T;
value: T;
}
// 使用示例
const myIdentity: GenericIdentity<number> = {
(arg: number): number { return arg },
value: 123
};
3. 泛型类
typescript
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
constructor(zero: T, addFn: (x: T, y: T) => T) {
this.zeroValue = zero;
this.add = addFn;
}
}
// 使用示例
const myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y);
泛型约束
有时我们需要限制泛型可以接受的类型范围:
typescript
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在我们知道arg一定有length属性
return arg;
}
// 正确
loggingIdentity("hello");
loggingIdentity([1, 2, 3]);
// 错误
// loggingIdentity(3); // 数字没有length属性
多个类型参数
泛型可以使用多个类型参数:
typescript
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
const p1 = pair<string, number>("hello", 42);
const p2 = pair(123, "world"); // 类型推断
实际应用场景
1. 通用数据容器
typescript
class Container<T> {
private data: T;
constructor(value: T) {
this.data = value;
}
getData(): T {
return this.data;
}
setData(value: T): void {
this.data = value;
}
}
const numberContainer = new Container<number>(123);
const stringContainer = new Container<string>("hello");
2. API 响应处理
typescript
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
async function fetchData<T>(url: string): Promise<ApiResponse<T>> {
const response = await fetch(url);
return response.json();
}
// 使用示例
interface User {
id: number;
name: string;
}
const result = await fetchData<User>('/api/user/1');
console.log(result.data.name);
总结
命名约定:通常使用单个大写字母作为类型参数名称
- T 表示 Type
- K 表示 Key
- V 表示 Value
- E 表示 Element
适度使用:不是所有地方都需要泛型,过度使用会增加代码复杂度
提供默认类型:可以为泛型参数提供默认类型
typescript
interface Config<T = string> {
id: T;
name: string;
}
const config: Config = { id: "123", name: "test" }; // T 默认为 string
const numConfig: Config<number> = { id: 123, name: "test" };
泛型是 TypeScript 中最强大的特性之一,合理使用可以大大提高代码的复用性和类型安全性。在实际开发中,我们经常在以下场景中使用泛型:
- 编写通用工具函数
- 实现数据结构(如栈、队列、树等)
- 处理 API 请求响应
- 状态管理(如 Redux)
- 依赖注入系统