#Accessing two levels deep into a type schema with generics not working?

17 messages · Page 1 of 1 (latest)

normal silo
#

I'm trying to model an API in typescript, and implement simple request methods.

Typescript seems to be okay with one level deep of accessing the schema with generics but not two levels deep. Is there some good way to handle this?

This is what I've got: ...

lament caveBOT
#
mehdim#0

Preview:ts type APIEndpoints = { GET: { "/v1/foo/:id": { params: { ":id": string } response: { data?: { id: string } message: string errors?: any } ...

elfin bramble
#
async function fetchM<Method extends keyof APIEndpoints, Path extends keyof APIEndpoints[keyof APIEndpoints]>(apiPath: Path, params: APIEndpoints[Method][Path]['params']): Promise<APIEndpoints[Method][Path]['response']>

might work for you?

#

this avoids typing the Path as keyof APIEndpoints[Method][string]

normal silo
#

oh hmm i think that resolves (keyof APIEndpoints['GET'] & keyof APIEndpoints['POST'])

#

which is too narrow, like excludes the paths set

#

agh forgot to include the Method in my example, ideally I would be able to express it like this:

async function fetchM<Method extends keyof APIEndpoints, Path extends keyof APIEndpoints[Method]>(method: Method, apiPath: Path, params: APIEndpoints[Method][Path]['params']): Promise<APIEndpoints[Method][Path]['response']>
elfin bramble
#

it's more brittle sadly

lament caveBOT
#
webstrand#0

Preview:```ts
...
fetchGet('/v1/foo/:id/items', { ':id': '123' });

const ret = await fetchM("GET", "/v1/foo/:id/items", { ':id': ""});
// ^?```

elfin bramble
#

the gist of the idea is: since typescript doesn't think those keys exist reliably, promise to it that they do exist and provide a fallback if they don't

#

according to my logic, it's impossible for those keys not to exist

#

but if they don't exist: you will get errors if you try to pass any params, and you'll receive Promise<unknown> as the output, which should swiftly lead to compile errors if you try to use it in any way

elfin bramble
#

I found an alternative solution

declare function fetchM<
  Method extends keyof APIEndpoints,
  Path extends keyof Endpoints,
  Endpoints extends { [key: string]: { params: {}, response: unknown } } = APIEndpoints[Method],
>(
  method: Method,
  apiPath: Path,
  params: Endpoints[Path]['params']
): Promise<Endpoints[Path]['response']>
#

I don't prefer one over the other

normal silo
#

wow this is awesome

#

thanks so much

#

i kind of like the second solution, feels a bit cleaner/simpler to me