I am trying to write a groupBy generic function in Typescript. I wanted to limit the groupBy fields to keys of specific type for a given object. I am using the solution proposed here and it's working fine limiting the keys I can use. The problem occurs later:
type KeysMatchingType<T, V> = {[K in keyof T]-?: T[K] extends V ? K : never}[keyof T];
type GroupByAllowedType = string | number | boolean
function groupBy<T extends object>(arr: T[], prop: KeysMatchingType<T,GroupByAllowedType>): Map<GroupByAllowedType, T[]> {
const map: Map<GroupByAllowedType, T[]> = new Map()
return arr.reduce((acc, current) => {
const key = current[prop]
const val = acc.get(key)
if(val){
val.push(current)
} else {
acc.set(key, [current])
}
return acc
}, map)
}
at const val = acc.get(key)
Typescript is complaining that:
Type 'T[string]' is not assignable to type 'GroupByAllowedType'
even tho the key used to index T
is limited by type declaration for the parameter, e.g. prop
is such a key that T[prop]
should return either boolean
, string
or number
I am just wondering is this a limitation of Typescript or am I doing something wrong?
I guess I could use casting with as
, but generally I try to avoid it.
CodePudding user response:
Change the constraint from object
to this:
function groupBy<T extends Record<KeysMatchingType<T, GroupByAllowedType>, GroupByAllowedType>>(arr: T[], prop: KeysMatchingType<T, GroupByAllowedType>): Map<GroupByAllowedType, T[]> {
Similarly to this answer from a while ago, you're able to tell TypeScript that you only care about the keys of T
that correspond to GroupByAllowedType
simply by using a recursive constraint.
Then as you see here, this one change fixes the error :)