Finding Things

So far, the main program has picked the items by their position in the array. That's fragile: when an item is added at the start of the inventory, kira.inventory[0] is suddenly something else. It's better to look an item up by its name. And a function that finds something by name is useful for more than items: a hero in a party, a monster in a cave or a spell in a book have names too. So it'll be a generic function, as in the lesson on generics.

The type parameter T is the type of the things in the array. The function needs only one thing from them, a name, and that's what the constraint says: T extends { name: string }. Without it, TypeScript doesn't know whether a T has a name at all: main.ts(63,39): error TS2339: Property 'name' does not exist on type 'T'.

The array method find from the lesson on unions returns the first element for which the function returns true, or undefined when there's none. So the function returns T | undefined, and whoever calls it has to handle both cases. A different example, a function that finds something of a given level:

function findByLevel<T extends { level: number }>(things: T[], level: number): T | undefined {
    return things.find(thing => thing.level === level);
}

const party = [
    { name: "Bruno", level: 5 },
    { name: "Lena", level: 2 },
];
const quests = [
    { title: "Rats in the Cellar", level: 1 },
    { title: "The Troll Cave", level: 5 },
];

const hero = findByLevel(party, 2);
console.log(hero?.name);
const quest = findByLevel(quests, 3);
if (quest === undefined) {
    console.log("No quest for level 3");
} else {
    console.log(quest.title);
}

This prints:

Lena
No quest for level 3

One function works for heroes and quests alike, and the result keeps its full type: quest.title is fine, because there, T is the type of a quest. But TypeScript lets you use quest.title only after the check for undefined.

The main program will try to use three items by their names: the potion, the sword, and a dragon egg that Kira doesn't have. A for...of loop can go through an array written right in it: for (const name of ["Healing Potion", "Silver Sword", "Dragon Egg"]). If you pass what findByName returns straight to useItem, without the check, TypeScript reports it:

main.ts(90,31): error TS2345: Argument of type 'Item | undefined' is not assignable to parameter of type 'Item'.
  Type 'undefined' is not assignable to type 'Item'.

Instructions

Under useItem, write a generic function findByName<T extends { name: string }>(things: T[], name: string): T | undefined that returns the first thing with that name, using find.

In the main program, replace the two lines with useItem with a for...of loop over the names "Healing Potion", "Silver Sword" and "Dragon Egg". For each name, find the item in Kira's inventory with findByName. If it isn't there, print Kira has no Dragon Egg (the hero's name and the name you looked for); otherwise, print what useItem returns. The program ends like this:

Kira drinks Healing Potion: health 50/50
Kira equips Silver Sword
Kira has no Dragon Egg

Start programming for free

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

4/7