Volba správného typu

Když navrhujete typ, rozhodujete, jaká data může váš program obsahovat. Takhle by typ truhly zpočátku napsala spousta programátorů:

type Truhla = {
    jeZamcena: boolean;
    nazevKlice?: string; // jen u zamčených truhel
};

function otevriTruhlu(truhla: Truhla): string {
    if (truhla.jeZamcena) {
        return `Potřebujete ${truhla.nazevKlice}`;
    }
    return "Truhla se otevřela";
}

console.log(otevriTruhlu({ jeZamcena: false }));
console.log(otevriTruhlu({ jeZamcena: true }));

Vypíše:

Truhla se otevřela
Potřebujete undefined

Komentář říká, že název klíče mají jen zamčené truhly, ale typ to neříká. Typ dovolí zamčenou truhlu bez názvu klíče, kterou by nikdo nikdy neotevřel, a TypeScript nic nenamítne, když ji program vytvoří. Nepovinná vlastnost navíc komplikuje zbytek kódu: i po kontrole truhla.jeZamcena TypeScript ví jen to, že truhla.nazevKlice je typu string | undefined, protože v typu nic ty dvě vlastnosti nespojuje. V té větvi skončí truhla.nazevKlice.length chybou error TS18048: 'truhla.nazevKlice' is possibly 'undefined'.

Sjednocení oba stavy popíše přesně:

type Truhla =
    | { jeZamcena: false }
    | { jeZamcena: true; nazevKlice: string };

I true a false jsou literálové typy, takže značkou rozlišeného sjednocení může být i vlastnost typu boolean. S tímto typem je zamčená truhla bez názvu klíče chyba:

main.ts(13,26): error TS2345: Argument of type '{ jeZamcena: true; }' is not assignable to parameter of type 'Truhla'.
  Property 'nazevKlice' is missing in type '{ jeZamcena: true; }' but required in type '{ jeZamcena: true; nazevKlice: string; }'.

Uvnitř if (truhla.jeZamcena) teď TypeScript ví, že truhla má nazevKlice typu string, bez undefined. A odemčená truhla s názvem klíče je chyba také (TS2353).

Programátoři tomu říkají „udělat nemožné stavy nemožnými“: dobrý typ dovolí jen data, která dávají smysl. Ve svých typech hledejte tyto příznaky:

  • boolean a nepovinné vlastnosti, které mají smysl, jen když je true, nebo jen když je false,
  • několik nepovinných vlastností, které jsou vždycky buď všechny, nebo žádná,
  • stav: string a komentáře o tom, které vlastnosti patří ke kterému stavu.

Za každým z nich se skrývá sjednocení, které čeká, až ho napíšete. Když jsou stavy víc než dva, použijte místo boolean textovou značku, třeba stav: "bojuje" | "utika" | "porazena".

Pokyny

Program dvakrát vypíše undefined, protože dvě příšery v seznamu nemůžou existovat. Nahraďte typ Prisera sjednocením příšery, která bojuje, { jmeno: string; jePorazena: false; zivoty: number }, a poražené příšery, { jmeno: string; jePorazena: true; vitez: string }. TypeScript pak obě příšery ohlásí. Opravte je: troll pořád bojuje a má 40 životů, kostlivce porazil Bruno. Program pak vypíše:

Vlk má 30 životů
Skřet je poražen, vítěz: Kira
Troll má 40 životů
Kostlivec je poražen, vítěz: Bruno

Pod cyklus napište funkci porazit s parametry prisera (typu Prisera) a hrdina (text) a s návratovým typem Prisera. Vrátí novou, poraženou příšeru se stejným jménem, kterou porazil hrdina. (Bez návratového typu by TypeScript u jePorazena: true odvodil jen boolean a nová příšera by do typu Prisera nepasovala.) Vypište popisPrisery(porazit(prisery[0], "Lena")). Program pak vypíše:

Vlk má 30 životů
Skřet je poražen, vítěz: Kira
Troll má 40 životů
Kostlivec je poražen, vítěz: Bruno
Vlk je poražen, vítěz: Lena

Začněte programovat zdarma

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

Nebo se registrujte pomocí:

7/8