tipizare - Typescript keyof unde valoarea are tip


Încerc să scriu o funcție în Typescript care primește:

  • un obiect care are cel puțin un membru de tip X (în acest exemplu: boolean)
  • o cheie a obiectului care indică valoarea respectivă

    (de ex. {someValue: true} -> key="someValue")

În prezent, abordarea mea este următoarea:

function myFunction<
    T extends Record<K, boolean>, // the type of the object
    K extends keyof T, // the key which points to X
>(
    obj: T,
    objKey: K,
) {
    const x: boolean = obj[objKey];
}

Acest lucru funcționează atâta timp cât am nevoie ca obiectul să fie de tip T și fără tipuri suplimentare. Totuși, acum am nevoie de un obiect care să implementeze atât T (un obiect cu un membru boolean), cât și AdditionalData. Totuși, dacă înlocuiesc T extends Record<...> cu T extends Record<...> & AdditionalData, verificarea tipului, desigur, eșuează.

Soluția la care m-am gândit a fost să introduc un alt tip generic L, care include doar date din SomeInterface și să fac ca K să depindă de acesta:

function myFunction<
    L extends Record<K, boolean>, // the type containing the boolean value
    K extends keyof L, // the key which points to X,
    T extends L & AdditionalData, // the type of the object
>(...) {}

Cu toate acestea, nici aceasta nu funcționează.

Există vreo modalitate de a forța ca valoarea indicată de o cheie să fie de un anumit tip?

EDIT: alternativ, există vreo modalitate de a exclude o valoare specifică din keyof? În acest fel, aș putea pur și simplu să exclud orice tipuri suplimentare din K...

Răspuns #1

Typescript nu raționează întotdeauna foarte bine despre tipul câmpurilor parametrilor generici. Nu sunt sigur exact ce cauzează faptul că nu recunoaște că obj[objKey] este un boolean, dar o soluție simplă este să folosești o variabilă suplimentară:

interface AdditionalData {
    a: number,
    b: string
}

function myFunction<
    T extends Record<K, boolean> & AdditionalData, // the type of the object
    K extends keyof T, // the key which points to X
>(
    obj: T,
    objKey: K,
) {
    const o : Record<K, boolean>= obj; // assignable
    const x: boolean = o[objKey]; // access works ok
}