I want to ask about Record in TypeScript, currently when I use Record as parameter type in a function then I get error in my code because it can't accept different type.
type Keys = 'name' | 'qty';
const getValueByKey = <T = any>(items: Record<Keys, T>, key: Keys) => {
return items[key];
}
getValueByKey({ name: 'fulan', qty: 1}, 'name'); // Error: Type 'number' is not assignable to type 'string'.(2322)
The goal is actually to get the type of the value in the function.
How can I make a Record accept values of different types? Thank you
CodePudding user response:
It seems like what you want to do is to accept an object type that has the keys in your union, and return a value from the object based on the key
parameter while also inferring what constitutes a valid key
parameter from the object that is provided. This type of inference is possible using generic constraints.
Keep in mind that TypeScript is structurally typed, so any object that has the keys
name
andqty
will be allowed (even if it has additional keys), and you'll be able to use any key from that object for thekey
argument.
type Key = 'name' | 'qty';
function getValueByKey <
T extends Record<Key, any>,
K extends keyof T,
>(items: T, key: K): T[K] {
return items[key];
}
const obj = {name: 'fulan', qty: 1};
const value1 = getValueByKey(obj, 'name');
//^? const value1: string
const value2 = getValueByKey(obj, 'qty');
//^? const value2: number
and if you try to use a key that's not in the object, TS will (appropriately) emit a compiler diagnostic error:
const value3 = getValueByKey(obj, 'not_a_key');
// ~~~~~~~~~~~
// Argument of type '"not_a_key"' is not assignable to parameter of type '"name" | "qty"'. (2345)