#How to correctly infer a keyof on an array in generic methods

23 messages · Page 1 of 1 (latest)

languid plinth
#

We created a pipe that sorts an array and that have sort options.
The options are an array of SortOption ts interface SortOption<Type, Key extends keyof Type, Value> { property: Key; order?: 'asc' | 'desc'; transformFn?: (value: Type[Key]) => Value; }

What we expect:
The option transformFn must have its value argument well inferred corresponding of the option property (for each option in our options array)

What we currently have:
The option transformFn has its value argument type inferred with the union return type of all the keys of Type (you can see an example on the screenshots below)

brisk kettle
languid plinth
#

Yeah I can do that! I currently don’t have my computer but I’ll do it as soon as possible

languid plinth
# brisk kettle could you share some code that demonstrates the problem (like what's in your scr...

A angular-cli project based on @angular/animations, @angular/compiler, @angular/core, @angular/common, @angular/platform-browser-dynamic, @angular/forms, @angular/platform-browser, rxjs, tslib, zone.js and @angular/router.

languid plinth
#

Nobody has an idea?

brisk kettle
#

if you're willing to change the call sites to be varargs-style with a rest parameter rather than using an array you can do something like this:

steady riverBOT
#
mkantor#7432

Preview:```ts
interface SortOption<
Type,
Key extends keyof Type,
Value

{
property: Key
order?: "asc" | "desc"
transformFn?: (value: Type[Key]) => Value
}

type SortOptions<
Type,
Keys extends readonly (keyof Type)[],
Value

= {
[I in keyof Keys]: SortOption<Type, Keys[I], Value>
...```

brisk kettle
#

that's the only way i know of to force typescript to infer the type of each array element individually while still applying a constraint. otherwise i think you'll need to write out more type annotations

#

(i simplified your example and removed all of the angular stuff to make it easier to play with, but hopefully you see how this can be applied to your code)

#

if you're willing to write as const at call sites you could do it with an array like this:

steady riverBOT
#
mkantor#7432

Preview:```ts
interface SortOption<
Type,
Key extends keyof Type,
Value

{
property: Key
order?: "asc" | "desc"
transformFn?: (value: Type[Key]) => Value
}

type SortOptions<
Type,
Keys extends readonly (keyof Type)[],
Value

= {
[I in keyof Keys]: SortOption<Type, Keys[I], Value>
...```

brisk kettle
#

but to my personal taste the varargs style in my previous playground feels nicer for this

languid plinth
#

Thank you very much for your answer! I also prefer the first one! 😄 I need to practice generic types some more now! I still lack some knowledge about it 😜

languid plinth
#

Do you maybe have some great resources to reach your knowledge of TS generic types? I know that I lack some knowledge and would like to learn it much much better

#

is the TS doc enough? (I admit that I never fully read it, only some parts of it when I needed)

brisk kettle
#

the page on generics is pretty good:

#

!hb generics

steady riverBOT
brisk kettle
#

but yeah, reading through the whole thing at some point is useful. you can skim the parts that seem comfortable to you already, but it's roughly ordered in a way that makes sense, so i recommend starting from the beginning

#

other than that really just playing around with stuff a lot. it'll become ingrained after a while

#

hanging out on this server helps too 🙂