Record
Some data form a table: one value for each member of a literal union. When a hero defeats a monster, she gets experience points (XP), and how many depends on the monster's type:
type MonsterType = "wolf" | "troll" | "dragon";
const xpFor = {
wolf: 15,
troll: 40,
};Somebody forgot the dragon. TypeScript can't know that this object should have a key for every MonsterType, unless you tell it. For that, it has a ready-made type, Record:
type MonsterType = "wolf" | "troll" | "dragon";
const xpFor: Record<MonsterType, number> = {
wolf: 15,
troll: 40,
};main.ts(3,7): error TS2741: Property 'dragon' is missing in type '{ wolf: number; troll: number; }' but required in type 'Record<MonsterType, number>'.Record<MonsterType, number> means “an object with exactly the keys from MonsterType, and a number for each of them”. You give Record two types in angle brackets: first the type of the keys, then the type of the values. (How types with angle brackets work, and how to write your own, you'll learn in the Generics lesson.) TypeScript then checks the table. A missing key gives TS2741, as above. A misspelled key, such as dragn: 100, gives:
main.ts(6,5): error TS2561: Object literal may only specify known properties, but 'dragn' does not exist in type 'Record<MonsterType, number>'. Did you mean to write 'dragon'?And a value of the wrong type, such as wolf: "15", gives TS2322.
You read the table with square brackets, as you did with stock[fruit] in the JavaScript course:
type MonsterType = "wolf" | "troll" | "dragon";
type Monster = { name: string; type: MonsterType };
const xpFor: Record<MonsterType, number> = {
wolf: 15,
troll: 40,
dragon: 100,
};
const grak: Monster = { name: "Grak", type: "troll" };
console.log(`${grak.name} gives ${xpFor[grak.type]} XP`);This prints:
Grak gives 40 XPThe type of grak.type is MonsterType, so TypeScript knows that the key exists, and the result is a number. With a key that is just any text, reading is an error, because the text might not be a key at all. Put these two lines right under the table's };, on lines 9 and 10:
const key: string = "troll";
console.log(xpFor[key]);main.ts(10,13): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Record<MonsterType, number>'.
No index signature with a parameter of type 'string' was found on type 'Record<MonsterType, number>'.The message says that TypeScript can't use a string to read from a Record<MonsterType, number>, so the result would have the type any. The fix is to give the key the right type, MonsterType.
A Record is handy for counting too. Start every key at 0, and add one in a loop:
type MonsterType = "wolf" | "troll" | "dragon";
type Monster = { name: string; type: MonsterType };
const defeated: Monster[] = [
{ name: "Grak", type: "troll" },
{ name: "Fang", type: "wolf" },
{ name: "Shadow", type: "wolf" },
];
const counts: Record<MonsterType, number> = { wolf: 0, troll: 0, dragon: 0 };
for (const monster of defeated) {
counts[monster.type]++;
}
console.log(counts);This prints:
{ wolf: 2, troll: 1, dragon: 0 }Instructions
Give prices the type Record<Rarity, number>. TypeScript then reports the missing price: add it. A legendary item costs 200 gold.
Print the price of every item in the inventory, using prices and the item's rarity. The program then prints:
Rope: 10 gold
Silver Sword: 50 gold
Dragon Egg: 200 gold
Torch: 10 goldCount the items of each rarity in const counts: Record<Rarity, number>, and print the counts at the end:
Rope: 10 gold
Silver Sword: 50 gold
Dragon Egg: 200 gold
Torch: 10 gold
Common: 2, rare: 1, legendary: 1Start programming for free
4/8