TypeScript 泛型与 ReturnType 详解
泛型基础概念
泛型(Generics)是 TypeScript 中创建可重用组件的核心特性,它允许我们在定义函数、接口或类时使用类型参数,而不是具体的类型。
基础泛型函数
typescript
// 最简单的泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 带有额外属性的泛型函数
function fetchData<T>(data: T) {
return {
data,
timestamp: Date.now()
}
}
ReturnType 与泛型函数
ReturnType
是 TypeScript 内置的工具类型,用于获取函数的返回类型。当与泛型函数结合使用时,它可以推导出具体的返回类型。
基本用法
typescript
function fetchData<T>(data: T) {
return {
data,
timestamp: Date.now()
}
}
// 使用 ReturnType 获取具体泛型实例的返回类型
type StringResult = ReturnType<typeof fetchData<string>>;
// 等价于: { data: string; timestamp: number }
type NumberResult = ReturnType<typeof fetchData<number>>;
// 等价于: { data: number; timestamp: number }
泛型约束
泛型约束允许我们限制泛型参数的类型范围。
接口约束
typescript
interface HasId {
id: number;
}
function processWithId<T extends HasId>(item: T) {
return {
...item,
processedAt: new Date()
}
}
type ProcessedResult = ReturnType<typeof processWithId<{ id: number; name: string }>>;
// { id: number; name: string; processedAt: Date }
联合类型约束
typescript
function handleUnion<T extends string | number>(value: T): T {
return value;
}
type StringResult = ReturnType<typeof handleUnion<string>>; // string
type NumberResult = ReturnType<typeof handleUnion<number>>; // number
多个泛型参数
typescript
function createPair<K, V>(key: K, value: V): [K, V] {
return [key, value];
}
type StringNumberPair = ReturnType<typeof createPair<string, number>>; // [string, number]
type BooleanStringPair = ReturnType<typeof createPair<boolean, string>>; // [boolean, string]
泛型默认值
typescript
function createConfig<T = string>(value: T) {
return {
value,
createdAt: Date.now()
}
}
// 使用默认类型
type DefaultConfig = ReturnType<typeof createConfig>; // { value: string; createdAt: number }
// 指定具体类型
type NumberConfig = ReturnType<typeof createConfig<number>>; // { value: number; createdAt: number }
泛型与条件类型
typescript
// 条件返回类型
function transformValue<T>(value: T): T extends string ? string : T extends number ? number : T {
if (typeof value === 'string') {
return value.toUpperCase() as any;
}
return value as any;
}
type StringTransform = ReturnType<typeof transformValue<string>>; // string
type NumberTransform = ReturnType<typeof transformValue<number>>; // number
type BooleanTransform = ReturnType<typeof transformValue<boolean>>; // boolean
泛型函数重载
typescript
// 函数重载声明
function parseInput<T extends string | number>(input: T): T extends string ? string : number;
// 函数实现
function parseInput(input: any): any {
if (typeof input === 'string') {
return input.trim();
}
return Number(input);
}
type StringParse = ReturnType<typeof parseInput<string>>; // string
type NumberParse = ReturnType<typeof parseInput<number>>; // number
异步函数与泛型
typescript
async function fetchApi<T>(url: string): Promise<T> {
const response = await fetch(url);
return response.json();
}
type ApiResponse = ReturnType<typeof fetchApi<{ data: string }>>;
// Promise<{ data: string }>
// 提取 Promise 的泛型类型
type UnpackPromise<T> = T extends Promise<infer U> ? U : T;
type ApiData = UnpackPromise<ApiResponse>; // { data: string }
泛型类方法
typescript
class DataProcessor<T> {
process(data: T) {
return {
original: data,
processed: true,
timestamp: Date.now()
};
}
}
const stringProcessor = new DataProcessor<string>();
type StringProcessed = ReturnType<typeof stringProcessor.process>;
// { original: string; processed: boolean; timestamp: number }
const numberProcessor = new DataProcessor<number>();
type NumberProcessed = ReturnType<typeof numberProcessor.process>;
// { original: number; processed: boolean; timestamp: number }
泛型与映射类型
typescript
function createRecord<K extends string, V>(keys: K[], value: V): Record<K, V> {
const result = {} as Record<K, V>;
keys.forEach(key => {
result[key] = value;
});
return result;
}
type StringRecord = ReturnType<typeof createRecord<['name', 'age'], string>>;
// Record<"name" | "age", string>
type NumberRecord = ReturnType<typeof createRecord<['count', 'total'], number>>;
// Record<"count" | "total", number>
实际应用场景
API 响应处理
typescript
interface User {
id: number;
name: string;
email: string;
}
function createUserResponse<T extends User>(user: T) {
return {
success: true,
data: user,
timestamp: Date.now()
};
}
type UserResponse = ReturnType<typeof createUserResponse<User>>;
// { success: boolean; data: User; timestamp: number }
错误处理模式
typescript
function tryCatch<T>(fn: () => T): { success: true; data: T } | { success: false; error: Error } {
try {
return { success: true, data: fn() };
} catch (error) {
return { success: false, error: error as Error };
}
}
type StringResult = ReturnType<typeof tryCatch<() => string>>;
// { success: true; data: string } | { success: false; error: Error }
type NumberResult = ReturnType<typeof tryCatch<() => number>>;
// { success: true; data: number } | { success: false; error: Error }
高阶函数
typescript
function withLogging<T extends (...args: any[]) => any>(fn: T): T {
return ((...args: Parameters<T>) => {
console.log(`Calling function with args:`, args);
const result = fn(...args);
console.log(`Function returned:`, result);
return result;
}) as T;
}
const loggedFetchData = withLogging(fetchData);
type LoggedStringResult = ReturnType<typeof loggedFetchData<string>>;
// { data: string; timestamp: number }
高级技巧
类型推断与泛型
typescript
function inferType<T>(value: T) {
return {
value,
type: typeof value
};
}
type StringInferred = ReturnType<typeof inferType<string>>;
// { value: string; type: "string" }
type NumberInferred = ReturnType<typeof inferType<number>>;
// { value: number; type: "number" }
递归泛型类型
typescript
// 深度只读类型
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? T[P] extends Function
? T[P]
: DeepReadonly<T[P]>
: T[P];
};
function createReadonlyConfig<T>(config: T): DeepReadonly<T> {
return JSON.parse(JSON.stringify(config)) as DeepReadonly<T>;
}
type ReadonlyConfig = ReturnType<typeof createReadonlyConfig<{ api: { url: string } }>>;
// DeepReadonly<{ api: { url: string } }>
常见问题与解决方案
问题1:ReturnType 与泛型函数签名
typescript
// 错误:不能直接对泛型函数使用 ReturnType
// type Wrong = ReturnType<typeof fetchData>; // 错误!
// 正确:需要指定具体的泛型参数
type Correct = ReturnType<typeof fetchData<string>>;
问题2:泛型约束与 ReturnType
typescript
// 当泛型有约束时,ReturnType 会考虑约束
function processArray<T extends any[]>(arr: T): T {
return arr;
}
type ArrayResult = ReturnType<typeof processArray<number[]>>; // number[]
问题3:条件类型与 ReturnType
typescript
// 条件类型在 ReturnType 中的行为
function conditional<T>(value: T): T extends string ? "string" : "other" {
return (typeof value === 'string' ? "string" : "other") as any;
}
type StringCondition = ReturnType<typeof conditional<string>>; // "string"
type NumberCondition = ReturnType<typeof conditional<number>>; // "other"
最佳实践
1. 合理使用泛型约束
- 使用约束确保类型安全
- 避免过度约束限制灵活性
- 在文档中说明约束的含义
2. 利用 ReturnType 进行类型推导
- 使用 ReturnType 避免重复定义类型
- 在复杂函数中利用 ReturnType 推导返回类型
- 结合泛型创建灵活的类型系统
3. 类型安全与性能
- 泛型在编译时被擦除,不影响运行时性能
- 使用泛型约束在编译时捕获类型错误
- 避免不必要的复杂泛型嵌套
总结
泛型与 ReturnType 的结合为 TypeScript 提供了强大的类型推导能力:
- 泛型提供了代码重用和类型安全
- ReturnType 自动推导函数返回类型
- 泛型约束确保类型安全
- 条件类型提供灵活的类型逻辑
通过合理使用这些特性,可以创建出既类型安全又灵活可重用的代码库。