TypeScript泛型API调用类如何实现返回类型与参数类型推断?
封装API调用类的TypeScript类型推断问题
我希望编写一个封装API调用函数的类,以简化Vue页面代码。该类初始化时传入API调用方法,调用类的Call方法时需正确获取函数的返回类型。以下是我目前的实现代码:
class ApiCall<T extends (...args: Parameters<T>) => Promise<TResponce>, TResponce> { private Request: T public IsCalling = false public HasErrors = false public Error: HttpError | null = null public IsSuccessful = false constructor (request: T) { this.Request = request } Call (...callArgs: Parameters<T>): TResponce | null { this.IsSuccessful = false this.Error = null this.HasErrors = false this.IsCalling = true this.Request(...callArgs) .then((result) => { this.IsSuccessful = true return result }).catch((error) => { this.Error = error this.HasErrors = true }).finally(() => { this.IsCalling = false }) return null } public GetErrors (key: string): string[] | null { return this.Error?.ModelState?.[key] ?? null } }
当我尝试调用时:
var blogApiCall = new ApiCall(Services.API.Blogs.GetBlogBySlug) var result = blogApiCall.Call('slug')
result的类型为any。
我也曾尝试将返回类型改为ReturnType:
class ApiCall<T extends (...args: Parameters<T>) => ReturnType<T>> {
但由于Call方法要求Request是Promise类型,出现错误:
Property 'then' does not exist on type 'ReturnType'
有趣的是,我之前的版本可以正确推断返回类型,但无法处理参数:
class ApiCall2<T> { private Request: (...parameters: any) => Promise<T> public IsCalling = false public HasErrors = false public Error: HttpError | null = null public IsSuccessful = false constructor (request: (...parameters: any) => Promise<T>) { this.Request = request } Call (...parameters: any): T | null { this.IsSuccessful = false this.Error = null this.HasErrors = false this.IsCalling = true this.Request(parameters) .then((result) => { this.IsSuccessful = true return result }).catch((error) => { this.Error = error this.HasErrors = true }).finally(() => { this.IsCalling = false }) return null } public GetErrors (key: string): string[] | null { return this.Error?.ModelState?.[key] ?? null } }
我刚接触TypeScript,希望能得到相关技术帮助。
解决方案
核心问题有两个:一是泛型定义冗余且约束错误,二是Call方法同步返回null无法正确传递异步结果的类型。以下是修正后的实现:
// 先定义HttpError类型(如果未定义的话) type HttpError = { ModelState: Record<string, string[]> // 其他错误字段根据实际情况补充 } class ApiCall<T extends (...args: any[]) => Promise<any>> { private Request: T public IsCalling = false public HasErrors = false public Error: HttpError | null = null public IsSuccessful = false constructor(request: T) { this.Request = request } // 调整为异步方法,返回Promise,自动推断返回类型 async Call(...callArgs: Parameters<T>): Promise<Awaited<ReturnType<T>>> { this.IsSuccessful = false this.Error = null this.HasErrors = false this.IsCalling = true try { const result = await this.Request(...callArgs) this.IsSuccessful = true return result } catch (error) { this.Error = error as HttpError this.HasErrors = true throw error // 可选择抛出错误让调用者处理,或返回默认值 } finally { this.IsCalling = false } } public GetErrors(key: string): string[] | null { return this.Error?.ModelState?.[key] ?? null } }
关键改进点
- 简化泛型定义:仅传入API函数类型
T,约束它为返回Promise的函数,无需额外定义TResponce。 - 正确处理异步类型:用
Awaited<ReturnType<T>>提取Promise解析后的实际返回类型,同时将Call改为async方法,返回对应Promise类型。 - 修复参数传递:原
ApiCall2中this.Request(parameters)是把参数数组作为单个参数传递,修正为this.Request(...callArgs)展开参数。 - 错误处理优化:使用
try/catch替代链式调用,逻辑更清晰,同时可选择是否抛出错误让调用者处理。
使用示例
// 假设Services.API.Blogs.GetBlogBySlug的类型是(slug: string) => Promise<Blog> const blogApiCall = new ApiCall(Services.API.Blogs.GetBlogBySlug) // result的类型自动推断为Blog const result = await blogApiCall.Call('slug')
这样既保留了类的状态管理(IsCalling、HasErrors等),又能正确推断参数和返回类型,同时符合异步代码的最佳实践。
内容的提问来源于stack exchange,提问作者lunchtime949
相关产品推荐
相关产品推荐

