获取Typescript中深度嵌套的类型

zazmityj  于 2023-01-27  发布在  TypeScript
关注(0)|答案(1)|浏览(204)

我试图创建严格类型的函数来调用我的API。我的想法是创建包含所有所需数据的类型,如下所示:

type ApiRoutes = {
  '/user': {
    POST: {
      payload: { mydata: number }
      response: UserData
    }
    DELETE: {
      payload: string
      response: UserData
    }
    GET: {
      payload: string
      response: UserData
    }
  }
}

在我的函数中使用它:

const apicall = async <
  E extends keyof ApiRoutes,
  T extends keyof ApiRoutes[E],
  P extends ApiRoutes[E][T]['payload]
>(
  endpoint: E,
  method: T,
  payload: P
):Promise<R extends ApiRoutes[E][T]['response> => {
  //do stuff
}

然后这样称呼它:

apicall('/user', 'POST', {mydata: 5})
apicall('/user', 'DELETE', 'my text')

我的问题是我总是出错
类型“payload”不能用于索引类型“ApiRoutes[E][T]”
但是当我调用apiCall的时候,我得到了正确的自动完成。你知道我需要改变什么吗?我认为inferkey可能会有所帮助,但是我还没有尝试过它,所以我不知道如何使用它。

pw136qt2

pw136qt21#

我不完全确定为什么会发生这种情况......也许TS将方法的值视为泛型对象而不是精确对象(我不得不承认这看起来是一种奇怪的行为),但您可以通过引入两个带有infer键的中间类型来修复它,正如您所指出的:

type Payload<E extends keyof ApiRoutes, T extends keyof ApiRoutes[E]> = ApiRoutes[E][T] extends {payload:infer P} ? P : never;
type Resp<E extends keyof ApiRoutes, T extends keyof ApiRoutes[E]> = ApiRoutes[E][T] extends {response:infer R} ? R : never;

现在可以像这样重写函数:

const apicall = async <
  E extends keyof ApiRoutes,
  T extends keyof ApiRoutes[E],
  P extends Payload<E,T>
>(
  endpoint: E,
  method: T,
  payload: P
):Promise<Resp<E,T>> => {
  //do stuff
}

相关问题