目录
1. 泛型概述
泛型(Generics)是 TypeScript 提供的一种**类型参数化(Type Parameterization)**机制,允许在定义时不指定具体类型,而在使用时再传入具体类型。
示例:
function identity<T>(arg: T): T {
return arg;
}
console.log(identity<string>("Hello")); // "Hello"
console.log(identity<number>(123)); // 123
T
是一个泛型类型变量,它在调用 identity
时被替换为具体类型。
2. 为什么使用泛型
- 提升代码复用性:让代码支持不同类型,避免重复代码。
- 增强类型安全性:在编译期检查类型,避免运行时错误。
- 提高可读性和维护性:通过约束类型关系,提高代码的可理解性。
泛型 vs. any
any
失去了类型安全:function identityAny(arg: any): any { return arg; }
identityAny("Hello")
可能返回 任意类型,无法保证输入输出类型一致。- 泛型保持类型信息:
function identity<T>(arg: T): T { return arg; }
identity<string>("Hello")
返回值类型就是string
,不会变成any
。
3. 基本语法
泛型的基本语法:
function functionName<T>(arg: T): T {
return arg;
}
T
是一个类型变量,表示任意类型。- 在调用函数时,可以通过
<T>
传入具体类型:let output = functionName<number>(10); // 指定 T 为 number
4. 泛型函数
(1)泛型函数的定义
function reverseArray<T>(items: T[]): T[] {
return items.reverse();
}
console.log(reverseArray<number>([1, 2, 3])); // [3, 2, 1]
console.log(reverseArray<string>(["a", "b", "c"])); // ["c", "b", "a"]
(2)类型推导
TypeScript 可以自动推导泛型类型:
const numbers = reverseArray([1, 2, 3]); // TypeScript 推断 T 为 number
5. 泛型接口
(1)定义泛型接口
interface Pair<T, U> {
first: T;
second: U;
}
const p1: Pair<number, string> = { first: 1, second: "hello" };
const p2: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
(2)泛型函数 + 泛型接口
interface Repository<T> {
data: T[];
add: (item: T) => void;
getAll: () => T[];
}
class UserRepo implements Repository<string> {
data: string[] = [];
add(item: string) { this.data.push(item); }
getAll() { return this.data; }
}
const users = new UserRepo();
users.add("Alice");
console.log(users.getAll()); // ["Alice"]
6. 泛型类
(1)基本用法
class Box<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
}
const numberBox = new Box<number>(100);
console.log(numberBox.getValue()); // 100
(2)泛型约束
class KeyValuePair<K, V> {
constructor(public key: K, public value: V) {}
}
const pair = new KeyValuePair<string, number>("age", 25);
console.log(pair.key, pair.value); // "age" 25
7. 泛型约束
(1)约束为特定类型
function printLength<T extends { length: number }>(arg: T): void {
console.log(arg.length);
}
printLength("Hello"); // 5
printLength([1, 2, 3]); // 3
(2)约束为类
class Animal { name: string = ""; }
class Dog extends Animal { breed: string = ""; }
function createInstance<T extends Animal>(Ctor: new () => T): T {
return new Ctor();
}
const dog = createInstance(Dog);
console.log(dog instanceof Dog); // true
8. 泛型工具类型
TypeScript 提供了一些内置的泛型工具类型,如:
Partial<T>
:将对象的所有属性变为可选Readonly<T>
:将对象的所有属性变为只读Record<K, T>
:创建键值对类型Pick<T, K>
:选择对象的部分属性Omit<T, K>
:删除对象的部分属性
示例
interface User {
id: number;
name: string;
email: string;
}
const partialUser: Partial<User> = { name: "Alice" };
const readonlyUser: Readonly<User> = { id: 1, name: "Bob", email: "bob@example.com" };
// readonlyUser.name = "Charlie"; // ❌ 报错
9. 泛型高级用法
(1)默认泛型类型
function createPair<T = string, U = number>(a: T, b: U): [T, U] {
return [a, b];
}
const pair = createPair(); // 默认 T = string, U = number
(2)多重泛型约束
function merge<T extends object, U extends object>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
const result = merge({ name: "Alice" }, { age: 30 });
console.log(result); // { name: "Alice", age: 30 }
10. 最佳实践
✅ 使用明确的泛型名称(如 T
, U
, V
,避免 X
, Y
这种无意义的名称)
✅ 优先使用 extends
进行类型约束
✅ 避免滥用 any
,尽可能使用泛型
✅ 使用工具类型简化泛型代码
11. 参考资料
- TypeScript 官方文档:Generics
- MDN:TypeScript Generic
- TypeScript 深入指南:TypeScript Deep Dive
泛型是 TypeScript 强大的特性之一,能够提升代码的灵活性、复用性和类型安全性。熟练掌握泛型,将极大提升 TypeScript 编程能力! 🚀
发表回复