I want to make a function like
function sortByKey<T>(items: T[], key: string): T[] {
return items.sort((a, b) => a[key] - b[key]);
}
I need T[key]
to be a number
, but I'm not sure how to express that.
If I knew the key ahead of time I could obviously just do {key: number}
but that doesn't work here.
I tried something like sortByKey<K>(items: {[k: K]: number}[], key: K)
but that gives the error "An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead."
I looked into mapped types but they don't seem to do what I need. Is something like this possible in TypeScript?
CodePudding user response:
You probably want the function to be generic both in T
, the type of the items
elements, and in K
, the type of key
. You can constrain K
to be keylike (K extends PropertyKey
) and constrain T
to be a type with a number
value at key K
(T extends Record<K, number>
using the Record<K, V>
utility type):
function sortByKey<K extends PropertyKey, T extends Record<K, number>>(
items: T[],
key: K
): T[] {
return items.sort((a, b) => a[key] - b[key]);
}
You can't write {[k: K]: number}
because that's an index signature which can't be generic. But you can write {[P in K]: number}
using a mapped type. Mapped types are similar to but distinct from index signatures; see this answer for more information. Anyway, Record<K, number>
is an alias for {[P in K]: number}
, so you were getting close.