Reputation: 8357
I want to write a groupBy
function, so far the type system is not so happy with my work.
export function group<
T extends object,
K extends (keyof T & string),
R = T[K] extends string ? string : never
>(
data: T[],
groupBy: keyof T
): { [group: R]: T[] }
The first error that I got is that R
in { [group: R]: T[] }
is not string
or number
.
The signature actually doesn't work at all for the data set of
group([{ name: 'Johnny Appleseed', age: 17 }], 'name') // R should be string
group([{ name: 'Johnny Appleseed', age: 17 }], 'age') // R should be never
However, both R
is never
while K
is "name" | "age"
I have to manually narrow down type parameter with group<{name: string, age: number}, 'name'>
to make R
be string
.
Upvotes: 2
Views: 837
Reputation: 249656
An index signature must be either string
or number
. No union types, no generic types nothing else will do except string
or number
.
We can still achieve the behavior you want if you use two function signatures, one that accepts only string
keys and the other that only accepts number
keys:
export declare function group<T extends Record<K, string>, K extends string>(data: T[], groupBy: K): { [group: number]: T[] }
export declare function group<T extends Record<K, number>, K extends string>(data: T[], groupBy: K): { [group: string]: T[] }
let groupByString = group([{ name: 'Johnny Appleseed', age: 17 }], 'name')
let groupByNumber = group([{ name: 'Johnny Appleseed', age: 17 }], 'age')
Upvotes: 1