keyof

Někdy je klíč, který chcete přečíst, uložený v proměnné. V JavaScriptu byste napsali schopnosti[klic], s hranatými závorkami. V TypeScriptu:

type Schopnosti = { sila: number; obratnost: number; magie: number };
const kira: Schopnosti = { sila: 6, obratnost: 9, magie: 4 };
function hodnotaSchopnosti(schopnosti: Schopnosti, klic: string): number {
    return schopnosti[klic];
}
console.log(hodnotaSchopnosti(kira, "obratnost"));

TypeScript ohlásí:

main.ts(4,12): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Schopnosti'.
  No index signature with a parameter of type 'string' was found on type 'Schopnosti'.

TypeScript odmítne, protože klic může být jakýkoli text, třeba "magi", a typ Schopnosti má jen tři klíče. Pro každý jiný klíč by schopnosti[klic] bylo undefined, a ne číslo, takže TypeScript nedokáže říct, jaký typ výsledek má („implicitly has an 'any' type“).

Typ „jeden z klíčů typu Schopnosti“ se zapíše jako keyof Schopnosti:

type Schopnosti = { sila: number; obratnost: number; magie: number };
type NazevSchopnosti = keyof Schopnosti; // "sila" | "obratnost" | "magie"

keyof vezme objektový typ a vrátí sjednocení jeho klíčů jako literálových typů. Protože se počítá z typu, nemůže zastarat: když do typu Schopnosti přidáte klíč, bude ho mít i keyof Schopnosti. S klic: keyof Schopnosti je schopnosti[klic] dovolené a překlep v klíči se odhalí už tam, kde funkci voláte:

type Schopnosti = { sila: number; obratnost: number; magie: number };
const kira: Schopnosti = { sila: 6, obratnost: 9, magie: 4 };
function hodnotaSchopnosti(schopnosti: Schopnosti, klic: keyof Schopnosti): number {
    return schopnosti[klic];
}
console.log(hodnotaSchopnosti(kira, "obratnost"));
console.log(hodnotaSchopnosti(kira, "magi"));

TypeScript ohlásí:

main.ts(7,37): error TS2345: Argument of type '"magi"' is not assignable to parameter of type 'keyof Schopnosti'.

keyof a generika. Když mají vlastnosti různé typy, samotné keyof nestačí. Příšera má jméno jmeno (text) a životy zivoty (číslo). Funkce s parametrem klic: keyof Prisera vrací string | number: TypeScript neví, který klíč jí předáte, takže výsledek může být obojí. Generická funkce zachová přesný typ:

type Prisera = { jmeno: string; zivoty: number };

function ziskejVlastnost<K extends keyof Prisera>(prisera: Prisera, klic: K): Prisera[K] {
    return prisera[klic];
}

const troll: Prisera = { jmeno: "Troll", zivoty: 80 };
console.log(ziskejVlastnost(troll, "jmeno").toUpperCase());
console.log(ziskejVlastnost(troll, "zivoty") - 30);

Vypíše:

TROLL
50

K extends keyof Prisera je omezení: K musí být jeden z klíčů. A Prisera[K] znamená „typ vlastnosti K v typu Prisera“. Ve volání ziskejVlastnost(troll, "jmeno") je K typ "jmeno", takže výsledek je typu Prisera["jmeno"], tedy string. Pro "zivoty" je to number. (Víc o takových typech se dozvíte v lekci 9.)

Pokyny

Změňte typ parametru klic (pomocí keyof) tak, aby přijímal jen klíče typu Hrdina. TypeScript pak v jednom z volání najde chybně napsaný klíč. Opravte ho, aby program vypsal:

jmeno: Kira
uroven: 3

Napište generickou funkci ziskejVlastnost<K extends keyof Hrdina>(hrdina: Hrdina, klic: K): Hrdina[K], která vrátí vlastnost hrdiny s klíčem klic.

Na konec přidejte tyto dva řádky. Fungují, jen když ziskejVlastnost vrací přesný typ: pro "povolani" text, pro "zlato" číslo.

console.log(ziskejVlastnost(kira, "povolani").toUpperCase());
console.log(ziskejVlastnost(kira, "zlato") + 50);

Program vypíše:

jmeno: Kira
uroven: 3
HRANICAR
170

Začněte programovat zdarma

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

Nebo se registrujte pomocí:

8/9