typescript - Skapa Record-liknande typ från unionstyp


I Typescript skapade jag en unionstyp med en gemensam "type"-egenskap:

export type Instruction =
  | { type: 'local.set', name: string, value: Expression }
  | { type: 'i32.const', value: number }
  | { type: 'i32.add', left: Expression, right: Expression };

Och jag vill skapa ett objekt med värdet av 'type'-egenskapen som nyckel, och som värde en funktion. Så här:

const visitor: Record<Instruction['type'], (instruction: Instruction) => void> = {
   'local.set': (instruction) => {},
   'i32.const': (instruction) => {},
   'i32.add': (instruction) => {},
}

Men typningen av parametern 'instruction' är för generell för mig. Jag vill veta vilka egenskaper jag kan få åtkomst till på instruktionen från funktionens insida. Så hur kan jag skapa en Record-liknande typ med alla nycklarna i 'type'-egenskapen i Instruction-typen, och deras respektive Instruction-typ som värde?

Med andra ord; Typescript kan härleda typen om jag gör så här:

const instruction: Instruction = { type: 'local.set' }; // TS knows about the missing 'name' and 'value' properties

Men jag vill göra något som:

const instruction: Instruction[where type = 'local.set'] = { type: 'local.set' };

Är det möjligt, och hur?

Svar #1

Du kan använda en anpassad mappad typ för att mappa över unionen av type och sedan använda den villkorliga typen Extract för att få unionen som ingår från Instruction som har samma typ som den aktuella egenskapen:

export type Instruction =
    | { type: 'local.set', name: string, value: Expression }
    | { type: 'i32.const', value: number }
    | { type: 'i32.add', left: Expression, right: Expression };

type Visitor<T extends { type: string}> = {
    [P in T['type']]: (instruction: Extract<T, { type: P }>) => void
}
const visitor: Visitor<Instruction> = {
    'local.set': (instruction) => { instruction.name},
    'i32.const': (instruction) => { instruction.value },
    'i32.add': (instruction) => {  instruction.right },
}

Lekplatslänk

Relaterade artiklar