heyimalex / reselect-map

Selectors for mapping over collections
MIT License
185 stars 16 forks source link

Add typescript type definition file #9

Closed markwhitfeld closed 7 years ago

markwhitfeld commented 7 years ago

I am using your library from a typescript project.

Please could you add a typing definition to the project so that it can be used in a type safe way. Have a look at the 'reselect' module because they have done it there and your module is very similar.

Thanks!

heyimalex commented 7 years ago

This finna be a nightmare.

heyimalex commented 7 years ago

It looks like createArraySelector and createObjectSelector are trivial, albeit with some obnoxious codegen. Making the more generic createListSelector and createMapSelector work perfectly seems impossible without higher kinded types. The input collection could be done since the it just needs to adhere to an interface, but you'd have to manually write out the selector's result type. That's annoying but not necessarily a deal breaker. Maybe we could do something with default parameters to make it work decent out of the box. Thinking out loud...

heyimalex commented 7 years ago

Just off the cuff, the first two look roughly like this.

function createArraySelector<S, E, RN, T>(
  arraySelector: Selector<S, E[]>,
  selectorN: Selector<S, RN>,
  combiner: (elem: E, resN: RN) => T,
): Selector<S, T[]>

function createObjectSelector<S, E, RN, T>(
  objectSelector: Selector<S, { [string]: E }>,
  selectorN: Selector<S, RN>,
  combiner: (elem: E, resN: RN, key: string) => T,
): Selector<S, { [string]: T }>

I'm kinda convinced that the other two aren't possible, but someone smarter than me can take a crack at it.

markwhitfeld commented 7 years ago

That looks about right. As I mentioned above they would probably look very similar to the ones from the "reselect" module. I was going to try to do it myself and submit a pull request but I ran out of time today. I'll let you know if I start working on it. My next chance will probably be in a week's time.

heyimalex commented 7 years ago

I'm not sure if it works or what else needs to happen for it to be packaged up, but here is what I've done so far. Some good old fashioned string-based code generation. Anyone interested in getting type definitions added should try it out and let me know!

markwhitfeld commented 7 years ago

I tried it out and it works perfectly except for one small issue that an object map can be keyed on either a string or a number. I will submit a pull request shortly. The object selectors make use of a union type to support both string and number keyed values. eg:

type ObjectMap<T> = { [key: string]: T; } | { [key: number]: T; };

export function createObjectSelector<S, E, T>(
    selector1: Selector<S, ObjectMap<E>>,
    combiner: (elem: E, key: string) => T,
): OutputSelector<S, ObjectMap<T>, (elem: E, key: string) => T>;
// etc...
heyimalex commented 7 years ago

Thanks!