You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
  }
}

关键改进点

  1. 简化泛型定义:仅传入API函数类型T,约束它为返回Promise的函数,无需额外定义TResponce。
  2. 正确处理异步类型:用Awaited<ReturnType<T>>提取Promise解析后的实际返回类型,同时将Call改为async方法,返回对应Promise类型。
  3. 修复参数传递:原ApiCall2中this.Request(parameters)是把参数数组作为单个参数传递,修正为this.Request(...callArgs)展开参数。
  4. 错误处理优化:使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 22:35:20