Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create Record-like type from union type

In Typescript I created a union type with a shared "type" property:

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

And I want to create an object with the value of the 'type' property as key, and as value a function. Like so:

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

But the typing of the 'instruction' parameter is too generic for me. I want to know which properties I can access on the instruction from within the function. So how can I create a Record like type with all the keys of the 'type' property in the Instruction type, and their respective Instruction type as value?

In other words; Typescript can infer the type if I do this:

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

But I want to do something like:

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

Is that possible, and how?

like image 858
Wessel van der Linden Avatar asked Sep 14 '25 21:09

Wessel van der Linden


1 Answers

You can use a custom mapped type to map over the union of type and then use the Extract conditional type to get the union constituent from Instruction that has the same type as the current property:

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 },
}

Playground Link

like image 91
Titian Cernicova-Dragomir Avatar answered Sep 17 '25 15:09

Titian Cernicova-Dragomir