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?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With