简体   繁体   中英

Nested mapped types in TypeScript

I have this type:

type Requests = {
  "/endpoint": {
    POST: {
      body: any
      response: any
    }
    // ...
  }
  // ...
}

I want to map response to another value, but I get an error in vscode:

export type API = {
  [route in keyof Requests]: {
    [method in keyof Requests[route]]: {
      body: Requests[route][method]["body"] // 🚨 Type '"body"' cannot be used to index type 'Requests[route][method]'
      response: Requests[route][method]["response"] | { error: any } // 🚨 Type '"request"' cannot be used to index type 'Requests[route][method]'
    }
  }
}

Is there any way to accomplish this?

This should do what you want

type Requests = {
    "/endpoint": {
    POST: {
        body: string
        response: number
    }
    // ...
    },

}


export type API = {
    [route in keyof Requests]: {
        [method in keyof Requests[route]]: {
        body: Requests[route][method] extends { body: infer R } ? R : never
        response: (Requests[route][method] extends { response: infer R } ? R : never) | { error: any }
        }
    }
}

It appears typescript can't really generalize about any key that might be in that type, even though the list is finite and known. But it's easy to help it out.

If you specify the general format for the type:

type RequestsFormat = Record<string, { [key: string]: { body: any, response: any } }>

And then extend that:

interface Requests extends RequestsFormat {
  "/endpoint": {
    POST: {
      body: any
      response: any
    }
  }
}

Then typescript can figure out the rest.

Playground

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM