#Struggling with type inference, example codebase provided.

28 messages · Page 1 of 1 (latest)

elder spindle
#

Hello,

I am trying to wrap my head around providing type inference to consumers while prototyping a type safe wrapper around some other libraries.

The issue I am having (along with accompanying codebase) is here: https://github.com/Tracktile/Axiom/blob/broken-provider/example/index.tsx

As you see, on line 31 User.schema is properly inferred.

However, on line 32 direct.User.schema is NOT properly inferred and receives a wider typing.

The difference, is that direct is the result of my createApi function which essentially binds my model objects to a query client. What this function does works, its the type inference of the result I am having issues with.

I want line 32 to be inferred to be the same type as 33.

Please let me know if you see what I've missed. I did have this working at some point, and have been starring at it for to long now.

GitHub

A very opinionated API client with built in caching, offline storage, validation, and more. Powered internally by @tanstack/react-query. - Axiom/index.tsx at broken-provider · Tracktile/Axiom

quartz spire
#

i'm not sure

  M extends ModelFactoryMap<T, S>,
  T extends ModelFactory<S>,
  S extends TSchema
``` is a good idea
#

any reason youre not using this instead?

  M extends Record<string, ModelFactory<any>>
elder spindle
#

The only reason would be my own lack of understanding. With string as the record index type the object keys wouldn't be typed though, right?

ie. direct.<AnyString> would work, rather than only the keys for the models provided, which was my goal.

quartz spire
elder spindle
#

Would M extends Record<keyof M, ModelFactory<any>> solve that?

#

Oh, I guess I have more to learn here.

#

I see now, because its in extends its not the same as a plain old type definition .

quartz spire
#

yea

#

the issue with M, T, S is that all your schemas must be the same type

#

because there's only one S

#

plus i'm guessing that it's hard for typescript to infer T and/or S, if it can even infer them at all

#

you can hover over createApi to check what the generic parameters are being inferred as

elder spindle
#

So in this type:

export type ModelMap<M extends Record<string, ModelFactory<any>>> = {
  [K in keyof M]: Model<S>;
};
#

What would Model<S> become? Since S is now longer a generic.

quartz spire
#

Model<M[K]> probably

#

well actually

#

i have no clue how ModelFactory and TSchema are related

elder spindle
#

ModelFactory is a function that takes a query client and returns a Model<T> where T must extend TSchema

quartz spire
#

so maybe ReturnType<M[K]>

elder spindle
#

YES.

Did did the trick:

export type ModelMap<M extends Record<string, ModelFactory<any>>> = {
  [K in keyof M]: ReturnType<M[K]>;
};
#

Thank you!!!!

#

ReturnType<M[K]> is Model<T>

quartz spire
#
type UnModelFactory<T> = T extends ModelFactory<infer U> ? U : never;
#

^- this is viable for more complicated generic types

#

it's also less reliable in certain cases (namely, cases where typescript forgets something is a ModelFactory - in this case ModelFactory is simple enough that it should never happen)

quartz spire
elder spindle
#

Yeah, i just got it inferring through the react provider and hook I had in hooks.tsx as well, its working exactly as indended.