Zobecnění keyof v TypeScriptu rubrika: Programování: JavaScript

5 vit.herman
položil/-a 20.2. 20:28
 
upravil/-a 20.2. 20:29

Zdravím všechny,

rád bych zobecnil typ keyof x v TypeScriptu tak, abych mohl odkazovat do libovolné úrovně v objektu. Toto zobecnění nazvěme typovanou cestou.

Mějme objekt:

const person: Person = {
    jmeno: "Petr",
    prijmeni: "Novák",
    dite: {
        firstName: "Anna",
        lastName: "Nováková",
        vek: 5,
        hracka: {
            nazev: "pandulak"
        }
    }
}

Stejně jako lze napsat:

const path: keyof Person ="jmeno";

tak bych potřeboval napsat:

const path: Path<Person> = ["dite", "hracka", "nazev"]

["dite", "hracka", "nazev"] pochopitelně má být kontrolováno na úrovni kompilace, že se jedná o validní cestu. Zdá se mi, že toto současný TypeScript neumožňuje. Dokáže mne někdo případně vyvést z omylu?

Pokus, se kterým jsem se dostal nejdále, je dokumentován zde https://gist.github.com/vimanvh/a8ca22fc887d5fb72e02f5db968d34aa

Díky moc za případné rady.

odkaz
7 David Macek
odpověděl/-a 20.2. 23:13

Začal jsem tři varianty bez konkrétní úrovně zanoření, ale ani jedna není funkční zatím. Třeba nějak pomůžou.

type Path<Obj, Key extends keyof Obj = never, Rest extends Path<Obj[Key]>|[] = []> = [Key, ...Rest];
 
type Path<Obj, Key extends string = ""> = [] | (Key extends keyof Obj ? [ Key, ...Path<Obj[Key]> ] : never);
 
type Path<Obj, Rest extends string[] = []> = Rest extends Path<Obj[infer Key extends keyof Obj]> ? [Key, ...Rest] : never;

Vložil bych jako komentář, ale kradlo mi to kusy kódu.

Komentáře

  • vit.herman : Super podnět, to využití rekurzivní definice. Cesta by mohla mít i tvar ["dite", ["hracka", ["nazev"]]]. To by pak mohlo fungovat i pro libovolnou hloubku. Můj nástin řešení funguje jen do pevně dané hloubky. I když je to pro mne zcela přijatelné omezení. Díky! 21.2. 11:26

Pro zobrazení všech 2 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.