null a undefined

Někdy hodnota chybí: hrdina nemá mazlíčka, truhla je prázdná, hledání nic nenajde. JavaScript má pro „nic“ dvě hodnoty. undefined dostanete z chybějící vlastnosti nebo argumentu. null programátoři ukládají schválně, když chtějí říct „tady nic není“. S null jste se setkali v kurzu JavaScriptu: vracela ho metoda querySelector(), když nenašla žádný prvek, a další řádek pak skončil chybou TypeError: Cannot read properties of null. Tahle chyba patří k nejčastějším chybám v programech v JavaScriptu.

V TypeScriptu mají null a undefined vlastní typy a ostatní typy je neobsahují. Do proměnné typu string tak null uložit nemůžete:

let cil: string = null;
main.ts(1,5): error TS2322: Type 'null' is not assignable to type 'string'.

Když hodnota může chybět, řeknete to sjednocením: Mazlicek | null je „mazlíček, nebo nic“. TypeScript pak dohlédne na to, abyste hodnotu před použitím zkontrolovali:

type Mazlicek = { jmeno: string; zvire: string };
type Hrdina = { jmeno: string; mazlicek: Mazlicek | null };

function popisMazlicka(hrdina: Hrdina): string {
    return `${hrdina.jmeno}: mazlíček ${hrdina.mazlicek.jmeno} (${hrdina.mazlicek.zvire})`;
}
main.ts(5,41): error TS18047: 'hrdina.mazlicek' is possibly 'null'.
main.ts(5,67): error TS18047: 'hrdina.mazlicek' is possibly 'null'.

„Possibly null“ znamená „možná null“: až funkce poběží, může být v hrdina.mazlicek hodnota null a čtení hrdina.mazlicek.jmeno by pak skončilo chybou TypeError: Cannot read properties of null (reading 'jmeno'). V JavaScriptu byste na to přišli, až by program spadl, a to jen v případě, že by někdo funkci zavolal pro hrdinu bez mazlíčka. TypeScript vám to řekne dřív, než program spustíte.

Opravou je kontrola a ta typ zúží stejně jako typeof:

type Mazlicek = { jmeno: string; zvire: string };
type Hrdina = { jmeno: string; mazlicek: Mazlicek | null };

function popisMazlicka(hrdina: Hrdina): string {
    if (hrdina.mazlicek === null) {
        return `${hrdina.jmeno}: žádný mazlíček`;
    }
    return `${hrdina.jmeno}: mazlíček ${hrdina.mazlicek.jmeno} (${hrdina.mazlicek.zvire})`;
}

const kira: Hrdina = { jmeno: "Kira", mazlicek: { jmeno: "Pip", zvire: "sova" } };
const bruno: Hrdina = { jmeno: "Bruno", mazlicek: null };
console.log(popisMazlicka(kira));
console.log(popisMazlicka(bruno));

Vypíše:

Kira: mazlíček Pip (sova)
Bruno: žádný mazlíček

Pod podmínkou s return je hrdina.mazlicek typu Mazlicek. Kontrolu můžete napsat i obráceně, if (hrdina.mazlicek !== null) { … }; pak je hrdina.mazlicek typu Mazlicek uvnitř složených závorek. Jak vidíte, zužování funguje i u vlastností, nejen u proměnných a parametrů.

mazlicek: Mazlicek | null není totéž co nepovinná vlastnost mazlicek?: Mazlicek. Tady musí být vlastnost uvedená vždycky a hrdina bez mazlíčka má mazlicek: null. Nepovinnou vlastnost můžete vynechat a její typ je Mazlicek | undefined: chybová hláška pak říká is possibly 'undefined' (TS18048) a hodnotu kontrolujete pomocí !== undefined.

Typická chyba: kontrola na špatné „nic“. if (hrdina.mazlicek !== undefined) nevyloučí null, takže u typu Mazlicek | null TypeScript dál hlásí 'hrdina.mazlicek' is possibly 'null'. Kontrolujte tu hodnotu, kterou typ obsahuje.

Pokyny

Spusťte program a opravte chyby pomocí kontroly: když je cil null, funkce vypíše Není na koho útočit a nic dalšího neudělá. Program pak vypíše:

Vlk má ještě 18 životů
Není na koho útočit

Kira si zatím nevybrala nový cíl. Pod volání vytvořte proměnnou (let) aktualniCil typu Prisera | null s hodnotou null a zavolejte utok(aktualniCil, 5).

Pak Kira zahlédne skřeta. Uložte do proměnné aktualniCil objekt { jmeno: "Skřet", zivoty: 20 } a znovu zavolejte utok(aktualniCil, 5). Program pak vypíše:

Vlk má ještě 18 životů
Není na koho útočit
Není na koho útočit
Skřet má ještě 15 životů

Začněte programovat zdarma

Registrací souhlasíte s provozními podmínkami a zásadami ochrany osobních údajů.

Nebo se registrujte pomocí:

4/10