typescript - Validera egenskap baserat på nycklar från en annan egenskap


Jag skulle vilja förbättra typkontrollen av följande objekt:

interface Config {
    fields: Record<string, unknown>;
    table: { id: string }[];
}

const config: Config = {
    fields: {
        id: {}
    },
    table: [
        { id: 'id' },
        { id: 'name' },
    ]
};

Den del jag har svårt med är att jag vill typkontrollera att table-objektets id ska matcha en nyckel i fields. Om table > id inte finns bland fields-nycklarna, så ska det ge ett fel. Så:

  • { id: 'id' } är OK, eftersom id-nyckeln finns i fields
  • { id: 'name' } borde ge ett fel, name-nyckeln finns inte i fields

Är detta möjligt? Plan B är att göra denna kontroll vid körning.

Svar #1

Det är inte möjligt (ännu) att skapa en fristående type som kan göra validering på det sättet. Men generiska type är tillräckligt kraftfulla för att uppnå detta. Generiska typer för validering används bäst i kombination med en funktion.

function useConfig<F>(config: { fields: F, table: { id: keyof F }[]}) {}

I denna funktion har vi den generiska typen F som innehåller information om objektet vi skickar med fields-egenskapen. Vi kan sedan använda keyof F inuti table.

Några tester för att validera resultatet:

useConfig({
    fields: {
        id: {}
    },
    table: [
        { id: 'id' }
    ]
})
// works

useConfig({
    fields: {
        id: {}
    },
    table: [
        { id: 'id' },
        { id: 'name' }
    ]
})
// error

useConfig({
    fields: {
        id: {},
        name: {}
    },
    table: [
        { id: 'id' },
        { id: 'name' }
    ]
})
// works

Lekplats

Svar #2

type fieldsType = {id:any}
const config:{fields:fieldsType, table:{[k:string]:keyof fieldsType}[]} = {
    fields: {
        id: {},
    },
    table: [
        { id: 'id' },
        { id: 'name' },
    ]
};