Let's say I want to write a sortBy
function, that takes a list of T
s and a key of T to sort the list by.
To properly work I want the key to only accept keys of T that are numeric.
I have this, but I don't know how to restrict Key
so that T[Key]
refers to a number:
const sortBy = <T, Key extends keyof T>(items: T[], key: Key) {
// impl
}
I played around with this, but could not get it to work:
type NumericAttributesOf<T> = {
[K in keyof T]: T[K] extends number ? T[K] : never
}
CodePudding user response:
It seems to be working for me, I think you forgot the arrow =>
in your sortBy function.
type NumericAttributesOf<T> = {
[K in keyof T]: T[K] extends number ? T[K] : never
}
// ||
// VV
const sortBy = <T, Key extends NumericAttributesOf<T>>(items: T[], key: Key) => {
// impl
}
sortBy([{
name: 'Test',
age: 20
}], 'name') // ERROR
sortBy([{
name: 'Test',
age: 20
}], 'age') // Ok
CodePudding user response:
There are two issues with
type NumericAttributesOf<T> = {
[K in keyof T]: T[K] extends number ? T[K] : never
}
T[K] extends number ? T[K] : never
selects value type while you're looking for key type, so it should be[K in keyof T]: T[K] extends number ? K : never
- The result of mapped type is an "object", you need to use lookup to extract union of allowed keys.
Here's a working example:
type NumericKeys<T> = {
[K in keyof T]: T[K] extends number ? K : never
}[keyof T]
const sortBy = <T, Key extends NumericKeys<T>>(items: T[], key: Key) => {
// impl
}
sortBy([{ str: 'str', num: 1}], 'str') // Error: Argument of type '"str"' is not assignable to parameter of type '"num"'
sortBy([{ str: 'str', num: 1}], 'num') // OK