Don't Use Any, Use Generics
// bad
const _getKeyValue = (key: string) => (obj: object) => obj[key];
// better
const _getKeyValue_ = (key: string) => (obj: Record<string, any>) => obj[key];
// best
const getKeyValue = <T extends object, U extends keyof T>(key: U) => (obj: T) =>
obj[key];
Bad - the reason for the error is the object
type is just an empty object by default. Therefore it isn't possible to use a string
type to index {}
.
Better - the reason the error disappears is because now we are telling the compiler the obj
argument will be a collection of string/value (string/any
) pairs. However, we are using the any
type, so we can do better.
Best - T
extends empty object. U
extends the keys of T
. Therefore U
will always exist on T
, therefore it can be used as a look up value.
Here is a full example:
I have switched the order of the generics (U extends keyof T
now comes before T extends object
) to highlight that order of generics is not important and you should select an order that makes the most sense for your function.
const getKeyValue = <U extends keyof T, T extends object>(key: U) => (obj: T) =>
obj[key];
interface User {
name: string;
age: number;
}
const user: User = {
name: "John Smith",
age: 20
};
const getUserName = getKeyValue<keyof User, User>("name")(user);
// => 'John Smith'
const getKeyValue = <T, K extends keyof T>(obj: T, key: K): T[K] => obj[key];