?. and ??
Checking for undefined with if works, but when all you want is a value or a replacement, it takes a lot of code:
type Weapon = { name: string; damage: number };
type Hero = { name: string; weapon?: Weapon };
const kira: Hero = { name: "Kira", weapon: { name: "Elven Bow", damage: 8 } };
const lena: Hero = { name: "Lena" };
let weaponName = "no weapon";
if (lena.weapon !== undefined) {
weaponName = lena.weapon.name;
}
console.log(weaponName);JavaScript has two operators that make this shorter, and TypeScript understands both of them.
The optional chaining operator ?. reads a property only if the value in front of it exists. lena.weapon?.name means: if lena.weapon is undefined or null, the result is undefined; otherwise, it's lena.weapon.name. No crash, no error:
type Weapon = { name: string; damage: number };
type Hero = { name: string; weapon?: Weapon };
const kira: Hero = { name: "Kira", weapon: { name: "Elven Bow", damage: 8 } };
const lena: Hero = { name: "Lena" };
console.log(kira.weapon?.name);
console.log(lena.weapon?.name);This prints:
Elven Bow
undefinedWith a plain dot, lena.weapon.name, TypeScript would report error TS18048: 'lena.weapon' is possibly 'undefined'. It also knows that the result of ?. may be missing: the type of lena.weapon?.name is string | undefined.
The nullish coalescing operator ?? gives a replacement for a missing value. a ?? b is a, unless a is null or undefined; then it's b. The two operators work well together:
console.log(kira.weapon?.name ?? "no weapon");
console.log(lena.weapon?.name ?? "no weapon");This prints:
Elven Bow
no weaponThe type of lena.weapon?.name ?? "no weapon" is just string: TypeScript knows that ?? filled in the missing case. You can store it in a string variable, or return it from a function that returns string. Without ??, the return of such a function is an error: Type 'string | undefined' is not assignable to type 'string'.
You may see || used for replacements too. Besides true and false, a || b works with any values: it gives a if a counts as true, and b otherwise. But 0 and the empty text "" count as false, so || replaces them too, while ?? replaces only null and undefined. With numbers, the difference matters:
const arrows = 0;
console.log(arrows || 10);
console.log(arrows ?? 10);This prints:
10
0A hero with no arrows has 0 arrows, not 10. When you mean “if it's missing”, use ??.
Typical mistake: ?. in the wrong place. It goes right after the value that may be missing: lena.weapon?.name, because weapon is optional. lena?.weapon.name checks lena, which always exists, and TypeScript still reports 'lena.weapon' is possibly 'undefined'.
Instructions
Lena has no weapon, so TypeScript reports hero.weapon.name. Fix the line with ?. and ??, so that a hero without a weapon gets the text no weapon. The program then prints:
Kira: Elven Bow
Bruno: Battle Axe
Lena: no weaponAdd the weapon's damage to each line. A hero without a weapon fights with bare hands, with damage 1: use ?. and ?? again. The program then prints:
Kira: Elven Bow (damage 8)
Bruno: Battle Axe (damage 11)
Lena: no weapon (damage 1)Add up the damage of all the heroes (again with 1 for bare hands), and print the total after the loop. The program then prints:
Kira: Elven Bow (damage 8)
Bruno: Battle Axe (damage 11)
Lena: no weapon (damage 1)
Total damage: 20Start programming for free
6/10