Zužování pomocí typeof

Funkce, která dostane string | number, obvykle potřebuje s každým typem zacházet jinak. V JavaScriptu typ zjistíte pomocí typeof, které znáte z kurzu JavaScriptu: typeof 50 je "number" a typeof "Stříbrný meč" je "string". TypeScript takové kontrole rozumí. V tomhle příkladu vyplácí cech odměny za úkoly a z každé odměny ve zlatě si 5 zlatých nechá pro sebe:

function vyplata(odmena: string | number): string {
    if (typeof odmena === "string") {
        return `Dostáváte ${odmena.toUpperCase()}`;
    } else {
        return `Dostáváte ${odmena - 5} zlatých (5 pro cech)`;
    }
}

console.log(vyplata("Stříbrný meč"));
console.log(vyplata(50));

Vypíše:

Dostáváte STŘÍBRNÝ MEČ
Dostáváte 45 zlatých (5 pro cech)

Uvnitř if TypeScript ví, že odmena je string, a proto dovolí toUpperCase(). Ve větvi else zbývá jen number, a tak dovolí odčítání. Tomu se říká zužování typu (anglicky narrowing): kontrola typ uvnitř větve zúží, ze string | number jen na string, nebo jen na number.

Bez kontroly TypeScript odčítání nedovolí:

function vyplata(odmena: string | number): string {
    return `Dostáváte ${odmena - 5} zlatých (5 pro cech)`;
}
main.ts(2,25): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.

Tuhle hlášku znáte z lekce Základní typy: hodnota vlevo od - musí být číslo.

Zužování funguje i bez větve else. Když větev if skončí příkazem return, zbytek funkce se provede jen pro druhý typ, a TypeScript to ví:

function vyplata(odmena: string | number): string {
    if (typeof odmena === "string") {
        return `Dostáváte ${odmena.toUpperCase()}`;
    }
    return `Dostáváte ${odmena - 5} zlatých (5 pro cech)`;
}

Pod podmínkou je odmena typu number. Programátoři funkce často píšou právě takhle: nejdřív zvláštní případ, který skončí příkazem return, a pak hlavní případ bez dalších složených závorek.

Sjednocení se objevují i v polích. Typ pole [12, "Starý klíč", 40] TypeScript odvodí jako (string | number)[]: pole, jehož prvky jsou texty nebo čísla. Když takový typ píšete sami, nezapomeňte na kulaté závorky. Bez nich znamená number | string[] „číslo, nebo pole textů“ a TypeScript čísla v poli odmítne:

const korist: number | string[] = [12, "Starý klíč", 40];
main.ts(1,36): error TS2322: Type 'number' is not assignable to type 'string'.
main.ts(1,54): error TS2322: Type 'number' is not assignable to type 'string'.

Typické chyby:

  • typeof vrací název typu malými písmeny: "string", "number", "boolean". Na typeof odmena === "String" TypeScript ohlásí error TS2367: This comparison appears to be unintentional because the types '"bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined"' and '"String"' have no overlap. Dlouhý seznam v hlášce ukazuje všechny texty, které může typeof vrátit, a "String" mezi nimi není.
  • Zúžený typ platí jen uvnitř větve, nebo pod podmínkou, která skončí příkazem return. Pod podmínkou bez return je typ zase string | number.

Pokyny

Spusťte program: TypeScript nedovolí cena * pocet, protože cena může být text. Na začátek funkce formatujCenu přidejte kontrolu pomocí typeof: když je cena text, funkce ho vrátí velkými písmeny. Program pak vypíše:

50 zlatých
ZDARMA

Pod volání vytvořte pole ceny typu (number | string)[] s hodnotami 12, "vyprodáno" a 40.

Projděte pole ceny cyklem for...of a pro každou cenu vypište formatujCenu(cena, 2). Program pak vypíše:

50 zlatých
ZDARMA
24 zlatých
VYPRODÁNO
80 zlatých

Začněte programovat zdarma

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

Nebo se registrujte pomocí:

2/10