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 undefinedKomentář ří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:
booleana nepovinné vlastnosti, které mají smysl, jen když jetrue, nebo jen když jefalse,- několik nepovinných vlastností, které jsou vždycky buď všechny, nebo žádná,
stav: stringa 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".
Jak psát:
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: BrunoPod 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: LenaZačněte programovat zdarma
7/8