TypeScript: Indexering i en objekttyp med hjälp av keyof
Jag har ett inbäddat objekt efter nycklar som ser ut som följer:
const OBJECTS = {
OBJECT1: {
properties: {
prop1: { value: "a" },
},
},
OBJECT2: {
properties: {
prop2: { value: "b" },
},
},
} as const;
Jag försöker skapa en generisk typ där jag kan extrahera egenskapsvärdena för ett specifikt objekt - något som:
type PropertiesForObject<OBJECT_KEY extends keyof typeof OBJECTS> = {
[PROPERTY_NAME in keyof typeof OBJECTS[OBJECT_KEY]["properties"]]: typeof OBJECTS[OBJECT_KEY]["properties"][PROPERTY_NAME]["value"];
};
Jag får dock följande felmeddelande:
Type '"value"' cannot be used to index type '{ readonly OBJECT1: { readonly properties: { readonly prop1: { readonly value: "a"; }; }; }; readonly OBJECT2: { readonly properties: { readonly prop2: { readonly value: "b"; }; }; }; }[OBJECT_KEY]["properties"][PROPERTY_NAME]'.
Finns det något sätt att indexera in i varje objekts egenskaper, givet att formen på egenskaperna är densamma? Jag skulle kunna tvinga det till ett gränssnitt, men jag vill behålla de starka typerna på värdena.
Svar #1
Detta kan mycket väl vara en bugg eller designbegränsning i TypeScript; kompilatorn känner inte igen att det generiska objektet kommer att ha en bokstavlig nyckel. Det är ett problem med den härledda begränsningen på typeof OBJECTS[K]["properties"][P]. Se microsoft/TypeScript#21760 för mer information (och ge det kanske en 👍 om du vill att det hanteras någon gång, men det ser inte lovande ut eftersom det har legat i vila i mer än två år från och med maj 2020).
Ett sätt att hantera detta är att göra typfunktionen mer generell (istället för typeof OBJECTS, använd en generisk typ T som uttryckligen begränsas till något med den struktur vi använder) och sedan specialisera den till typeof OBJECTS:
type GenericPropertiesForObject<
T extends Record<K, { properties: { [k: string]: { value: any } } }>,
K extends PropertyKey
> = {
[P in keyof T[K]["properties"]]: T[K]["properties"][P]["value"]
};
type PropertiesForObject<K extends keyof typeof OBJECTS> =
GenericPropertiesForObject<typeof OBJECTS, K>;
Detta kompilerar utan fel, även om det i princip utför samma beräkning. Låt oss se till att det fungerar:
type O1Props = PropertiesForObject<'OBJECT1'>;
// type O1Props = { readonly prop1: "a"; }
type O2Props = PropertiesForObject<'OBJECT2'>;
// type O2Props = { readonly prop2: "b"; }
Ser bra ut för mig. Okej, hoppas det hjälper; lycka till!
Lekplatslänk till kod
