Typové stráže

typeof rozliší texty od čísel. Co ale sjednocení dvou typů objektů? Pro oba vrátí typeof stejně "object":

type Lektvar = { nazev: string; leceni: number };
type Zbran = { nazev: string; poskozeni: number };
type Predmet = Lektvar | Zbran;

const inventar: Predmet[] = [
    { nazev: "Léčivý lektvar", leceni: 20 },
    { nazev: "Stříbrný meč", poskozeni: 12 },
];

U předmětu typu Predmet smíte číst nazev, který mají oba typy, ale ne leceni. V cyklu for (const predmet of inventar) skončí řádek console.log(predmet.leceni); chybou:

main.ts(11,25): error TS2339: Property 'leceni' does not exist on type 'Predmet'.
  Property 'leceni' does not exist on type 'Zbran'.

JavaScript má operátor, který zjistí, jestli má objekt nějakou vlastnost: "leceni" in predmet je true, když má predmet vlastnost leceni. TypeScript podle něj typ zužuje. Vlastnost leceni má jen Lektvar, takže uvnitř if je předmět typu Lektvar a ve větvi else typu Zbran:

for (const predmet of inventar) {
    if ("leceni" in predmet) {
        console.log(`${predmet.nazev} léčí ${predmet.leceni}`);
    } else {
        console.log(`${predmet.nazev} má poškození ${predmet.poskozeni}`);
    }
}

Vypíše:

Léčivý lektvar léčí 20
Stříbrný meč má poškození 12

Když stejnou kontrolu potřebujete na víc místech, budete ji chtít dát do funkce. Funkce, která vrací boolean, ale nic nezúží:

function jeLektvar(predmet: Predmet): boolean {
    return "leceni" in predmet;
}

for (const predmet of inventar) {
    if (jeLektvar(predmet)) {
        console.log(`${predmet.nazev} léčí ${predmet.leceni}`);
    }
}

TypeScript zase ohlásí Property 'leceni' does not exist on type 'Predmet'. Z návratového typu boolean se dozví jen to, že funkce vrací true nebo false, ne co to říká o předmětu. K tomu slouží zvláštní návratový typ predmet is Lektvar („předmět je lektvar“):

function jeLektvar(predmet: Predmet): predmet is Lektvar {
    return "leceni" in predmet;
}

Funkce dál vrací true nebo false, ale TypeScript teď ví: když vrátí true, je predmet typu Lektvar. Takové funkci se říká typová stráž (anglicky type guard). Podmínka if (jeLektvar(predmet)) pak typ zúží stejně jako kontrola in uvnitř funkce a ve větvi else je předmět typu Zbran. Před is stojí název parametru.

(Když návratový typ úplně vynecháte, současné verze TypeScriptu si predmet is Lektvar někdy odvodí samy. S : boolean jste jim ale řekli, že jde jen o pravdivostní hodnotu.)

Typické chyby:

  • TypeScript typové stráži věří: nekontroluje, jestli tělo funkce testuje správnou věc. Když omylem napíšete return "poskozeni" in predmet;, TypeScript bude považovat meče za lektvary a cyklus výše vypíše Stříbrný meč léčí undefined.
  • Překlep v názvu vlastnosti TypeScript také neohlásí. "lecen" in predmet je prostě u každého předmětu false, takže žádný předmět nikdy nebude lektvar.

V příští lekci uvidíte častější způsob, jak typy objektů rozlišit: vlastnost jako druh, která říká, co je každý objekt zač. Tam TypeScript takové překlepy zachytí.

Pokyny

V bitvě jsou hrdinové i příšery. Napište typovou stráž jePrisera s parametrem bojovnik typu Bojovnik: pomocí in zjistí, jestli je bojovník Prisera.

Projděte pole bitva cyklem for...of a pomocí jePrisera vypište každého bojovníka: příšeru s její silou, hrdinu s úrovní. Program pak vypíše:

Kira (úroveň 3)
skřet (síla 4)
Bruno (úroveň 2)
troll (síla 15)

Sečtěte sílu všech příšer a za cyklem ji vypište:

Kira (úroveň 3)
skřet (síla 4)
Bruno (úroveň 2)
troll (síla 15)
Síla příšer: 19

Začněte programovat zdarma

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

Nebo se registrujte pomocí:

9/10