TypeScript异步函数泛型:如何强制异步函数泛型与泛型返回类型?
实现带类型安全的异步重试工具函数(保留TypeScript类型信息)
要解决约束异步函数类型同时避免返回值双重包装的问题,关键是调整泛型约束的方式,直接将函数的返回值限定为PromiseLike<T>,让TypeScript自动推断内部值类型T,而非直接约束函数本身的泛型。
基础版实现(无参数函数)
export async function retry<T>(fn: () => PromiseLike<T>, retries: number = 1): Promise<T> { let attempts = 0; while (attempts < retries) { try { console.log(`Evaluating attempt #${attempts} ...`); return await fn(); } catch (e) { console.log(`Attempt #${attempts} failed.`); attempts++; if (attempts >= retries) { throw e; } } } throw new Error("Retry count must be at least 1"); }
关键说明
- 类型约束:通过
fn: () => PromiseLike<T>强制传入的函数必须返回Promise或PromiseLike对象,直接排除了同步函数的可能性。 - 返回类型处理:泛型
T代表异步函数resolve后的实际值类型,await fn()会自动提取PromiseLike<T>中的T,再由async函数包装为Promise<T>,完全不会出现Promise<Promise<T>>的双重包装问题。 - 逻辑修正:原代码最后一次失败时返回失败的Promise,这里改为直接抛出错误,让调用者能通过
catch捕获最终失败,更符合重试逻辑的预期。
进阶版实现(支持带参数的函数)
如果需要重试带参数的异步函数,可以扩展泛型支持参数类型推断:
export async function retry<T, Args extends any[]>( fn: (...args: Args) => PromiseLike<T>, retries: number = 1, ...args: Args ): Promise<T> { let attempts = 0; while (attempts < retries) { try { console.log(`Evaluating attempt #${attempts} ...`); return await fn(...args); } catch (e) { console.log(`Attempt #${attempts} failed.`); attempts++; if (attempts >= retries) { throw e; } } } throw new Error("Retry count must be at least 1"); }
这个版本会自动推断待重试函数的参数类型,调用时无需手动指定,比如:
// 示例:带参数的异步函数 async function fetchData(id: number): Promise<string> { if (Math.random() > 0.5) throw new Error("Fetch failed"); return `Data for ${id}`; } // 调用重试函数,参数类型自动匹配 retry(fetchData, 3, 123) .then(data => console.log(data)) .catch(err => console.error("Final failure:", err));
内容的提问来源于stack exchange,提问作者Spencer Duball
相关产品推荐
相关产品推荐

