You need to restrict K
to a string
and also you need to ensure that when indexing the accessed field is also a string, we can use a mapped type to ensure this:
interface CollectionById<T> {
[n: string]: T
}
export const arrayToCollection = <T extends { [P in K]: string }, K extends string>(
list: T[],
key: K
): CollectionById<T> => {
const collection: CollectionById<T> = {};
list.forEach((item: T) => {
collection[item[key]] = item;
});
return collection;
};
let list = [{ id: "A", age: 10 }, { id: "B", age: 10 }]
let grouped = arrayToCollection(list, 'id'); //ok
let grouped = arrayToCollection(list, 'age'); //error
Note We can also allow indexing by number
if we change the generic constraint to be T extends { [P in K]: string | number }
. Then we could also write:
let list = [{ id: 1, age: 10, data: {} }, { id: 2, age: 10, data: {} }]
let grouped = arrayToCollection(list, 'id');
let grouped3 = arrayToCollection(list, 'data'); // error neeed to be string or number