泛型(Generics)
概述
泛型是 TypeScript 的核心特性之一,允许我们编写可重用的组件,同时保持类型安全。
基本语法
泛型函数
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 类型推断
const num = identity(42); // T 推断为 number
const str = identity('hello'); // T 推断为 string
// 显式指定类型
const result = identity<number>(42);
const result2 = identity<string>('hello');
泛型接口
// 泛型接口
interface Container<T> {
value: T;
getValue(): T;
setValue(value: T): void;
}
// 实现泛型接口
class Box<T> implements Container<T> {
constructor(public value: T) {}
getValue(): T {
return this.value;
}
setValue(value: T): void {
this.value = value;
}
}
const numberBox = new Box<number>(42);
const stringBox = new Box<string>('hello');
泛型类
// 泛型类
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];
}
isEmpty(): boolean {
return this.items.length === 0;
}
}
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
numberStack.push(3);
const stringStack = new Stack<string>();
stringStack.push('a');
stringStack.push('b');
泛型约束
基本约束
// 泛型约束
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
logLength('hello'); // 正确
logLength([1, 2, 3]); // 正确
// logLength(42); // 错误:number 没有 length 属性
keyof 约束
// keyof 约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: 'John', age: 25 };
const name = getProperty(user, 'name'); // string
const age = getProperty(user, 'age'); // number
// getProperty(user, 'email'); // 错误:email 不是 User 的键
多重约束
// 多重约束
interface Printable {
print(): void;
}
interface Loggable {
log(): void;
}
function process<T extends Printable & Loggable>(item: T): void {
item.print();
item.log();
}
泛型工具类型
Partial
// Partial<T> - 将所有属性变为可选
interface User {
id: number;
name: string;
email: string;
}
type PartialUser = Partial<User>;
// 等价于:{ id?: number; name?: string; email?: string; }
function updateUser(id: number, updates: Partial<User>): void {
// 更新用户
}
updateUser(1, { name: 'Jane' }); // 正确
updateUser(1, { name: 'Jane', email: 'jane@example.com' }); // 正确
Required
// Required<T> - 将所有属性变为必需
interface User {
id?: number;
name?: string;
email?: string;
}
type RequiredUser = Required<User>;
// 等价于:{ id: number; name: string; email: string; }
Readonly
// Readonly<T> - 将所有属性变为只读
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
const user: ReadonlyUser = { id: 1, name: 'John' };
// user.name = 'Jane'; // 错误:只读属性
Record
// Record<K, V> - 创建键值对类型
type UserRoles = Record<number, string>;
const roles: UserRoles = {
1: 'admin',
2: 'user',
3: 'guest'
};
// 更复杂的例子
interface User {
id: number;
name: string;
}
type UserMap = Record<string, User>;
const users: UserMap = {
'user-1': { id: 1, name: 'John' },
'user-2': { id: 2, name: 'Jane' }
};
Pick
// Pick<T, K> - 选择部分属性
interface User {
id: number;
name: string;
email: string;
age: number;
}
type UserBasicInfo = Pick<User, 'id' | 'name'>;
// 等价于:{ id: number; name: string; }
Omit
// Omit<T, K> - 排除部分属性
interface User {
id: number;
name: string;
email: string;
age: number;
}
type UserWithoutAge = Omit<User, 'age'>;
// 等价于:{ id: number; name: string; email: string; }
Exclude 和 Extract
// Exclude<T, U> - 从联合类型中排除类型
type T1 = Exclude<'a' | 'b' | 'c', 'a'>; // 'b' | 'c'
type T2 = Exclude<string | number | (() => void), Function>; // string | number
// Extract<T, U> - 从联合类型中提取类型
type T3 = Extract<'a' | 'b' | 'c', 'a' | 'f'>; // 'a'
type T4 = Extract<string | number | (() => void), Function>; // () => void
NonNullable
// NonNullable<T> - 排除 null 和 undefined
type T1 = NonNullable<string | number | undefined>; // string | number
type T2 = NonNullable<string | null>; // string
ReturnType
// ReturnType<T> - 获取函数返回类型
function createUser() {
return { id: 1, name: 'John' };
}
type User = ReturnType<typeof createUser>;
// { id: number; name: string; }
Parameters
// Parameters<T> - 获取函数参数类型
function createUser(name: string, age: number) {
return { id: 1, name, age };
}
type CreateUserParams = Parameters<typeof createUser>;
// [string, number]
条件类型
基本条件类型
// 条件类型
type IsString<T> = T extends string ? true : false;
type T1 = IsString<string>; // true
type T2 = IsString<number>; // false
// 更复杂的例子
type Flatten<T> = T extends Array<infer Item> ? Item : T;
type T3 = Flatten<string[]>; // string
type T4 = Flatten<number[]>; // number
type T5 = Flatten<string>; // string
infer 关键字
// infer 关键字
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type T1 = ReturnType<() => string>; // string
type T2 = ReturnType<(x: number) => number>; // number
// 提取 Promise 类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type T3 = UnwrapPromise<Promise<string>>; // string
type T4 = UnwrapPromise<number>; // number
映射类型
基本映射类型
// 映射类型
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
type Required<T> = {
[P in keyof T]-?: T[P];
};
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
type PartialUser = Partial<User>;
自定义映射类型
// 自定义映射类型
type Nullable<T> = {
[P in keyof T]: T[P] | null;
};
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
interface User {
readonly id: number;
name: string;
}
type NullableUser = Nullable<User>;
type MutableUser = Mutable<User>;
实际应用示例
1. API 响应类型
type ApiResponse<T> = {
success: boolean;
data: T;
error?: string;
};
type PaginatedResponse<T> = ApiResponse<{
items: T[];
total: number;
page: number;
pageSize: number;
}>;
interface User {
id: number;
name: string;
}
type UserResponse = ApiResponse<User>;
type UsersResponse = PaginatedResponse<User>;
2. 状态管理
type LoadingState<T> = {
status: 'loading';
};
type SuccessState<T> = {
status: 'success';
data: T;
};
type ErrorState = {
status: 'error';
error: string;
};
type AsyncState<T> = LoadingState<T> | SuccessState<T> | ErrorState;
3. 表单类型
type FormField<T> = {
value: T;
error?: string;
touched: boolean;
};
type Form<T> = {
[K in keyof T]: FormField<T[K]>;
};
interface LoginForm {
username: string;
password: string;
remember: boolean;
}
type LoginFormFields = Form<LoginForm>;
最佳实践
- 使用泛型提高代码复用性
- 使用约束限制泛型类型
- 使用工具类型简化类型定义
- 避免过度使用泛型
// 好的做法
function identity<T>(arg: T): T {
return arg;
}
interface Repository<T> {
getById(id: number): T | null;
save(item: T): void;
}
// 避免
function identity(arg: any): any {
return arg;
}
参考
目录