typescript - Hur får man typeof nyckel i en lista med objekt?


Givet

type PageInfo = {
    title: string
    key: string
}

const PAGES: PageInfo[] = [
    {
        key: 'trip_itinerary',
        title: "Trip Itinerary",
    },
    {
        key: 'trip_details',
        title: "Trip Details",
    },
    {
        key: 'passenger_info',
        title: "Passenger Information",
    },
]

Kan jag ta ut en typ för key-tangenten som 'trip_itinerary'|'trip_details'|'passenger_info'? Jag vill använda den som nyckel för en Record, men jag vill helst inte skriva den manuellt.

Något som

type PageKey = typeof PAGES[???].key

Jag kan byta PAGES mot satifies om det hjälper...

const PAGES = [
    ...
] satisfies PageInfo[]

Svar #1

Om du annoterar PAGES som PageInfo[] kommer kompilatorn lydigt att utvidga PAGES till den typen, vilket gör att du kan push() godtyckliga PageInfo-instanser på den, omorganisera dess innehåll eller ändra key och egenskaper på någon av dess element. Kompilatorn glömmer avsiktligt bort den specifika ordningen eller innehållet i PAGES och deras särskilda egenskaper, eftersom dessa kan ändras. Men det är inte vad du vill.

Istället vill du att kompilatorn ska härleda typen av PAGES. Och om du vill att den härledda typen ska återspegla bokstavliga typer av key-egenskaperna från initialisatorn, kommer du förmodligen att vilja använda en const-påstående för att ge kompilatorn en ledtråd om att du bryr dig om sådana detaljer:

const PAGES = [
    {
        key: 'trip_itinerary',
        title: "Trip Itinerary",
    },
    {
        key: 'trip_details',
        title: "Trip Details",
    },
    {
        key: 'passenger_info',
        title: "Passenger Information",
    },
] as const;

Nu har PAGES typen

/* const PAGES: readonly [{
    readonly key: "trip_itinerary";
    readonly title: "Trip Itinerary";
}, {
    readonly key: "trip_details";
    readonly title: "Trip Details";
}, {
    readonly key: "passenger_info";
    readonly title: "Passenger Information";
}] */

och du kan beräkna PageKey på följande sätt:

type PageKey = typeof PAGES[number]["key"];
// type PageKey = "trip_itinerary" | "trip_details" | "passenger_info"

Det här fungerar som önskat, och du kan sluta där om du vill.

Ändå kommer kompilatorn inte bry sig om PAGES är en array av PageInfo-element eller inte. Om du vill att kompilatorn ska verifiera den typen utan att vidga till den, kan du använda satisfies-operatorn:

const PAGES = [
    {
        key: 'trip_itinerary',
        title: "Trip Itinerary",
    },
    {
        key: 'trip_details',
        title: "Trip Details",
    },
    {
        key: 'passenger_info',
        title: "Passenger Information",
    },
] as const satisfies readonly PageInfo[];

Observera att vi var tvungna att skriva satisfies readonly PageInfo[] istället för satisfies PageInfo[]. Det beror på att readonly X[]-arraytypen är bredare än den skrivbara X[]-arraytypen. Eftersom as const producerar readonly-arrayer, är det inte nödvändigtvis fallet att PAGES satisfies PageInfo[].

Hur som helst kommer kompilatorn nu att klaga om du inte initialiserar PAGES med giltiga PageInfo-element:

const PAGES_OOPS = [
    {
        key: 'trip_itinerary',
        title: "Trip Itinerary",
    },
    {
        key: 'trip_details',
        title: 123, // oops
    },
    {
        key: 'passenger_info',
        title: "Passenger Information",
    },
] as const satisfies readonly PageInfo[] // error!
// Type '{ readonly key: "trip_details"; readonly title: 123; }' 
// is not assignable to type 'PageInfo'.

Playground-länk till kod