Создать Record-like тип из объединения типа - PullRequest
1 голос
/ 01 мая 2020

В Typescript я создал объединенный тип с общим свойством type:

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

И я хочу создать объект со значением свойства type в качестве ключа и в качестве значения a функция. Вот так:

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

Но ввод параметра 'инструкция' для меня слишком обобщенный c. Я хочу знать, к каким свойствам я могу получить доступ к инструкции из функции. Итак, как я могу создать Record подобный тип со всеми ключами свойства 'type' в типе Instruction и их соответствующим типом Instruction в качестве значения?

Другими словами; Typescript может вывести тип, если я сделаю это:

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

Но я хочу сделать что-то вроде:

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

Возможно ли это и как?

1 Ответ

2 голосов
/ 01 мая 2020

Вы можете использовать пользовательский сопоставленный тип для сопоставления через объединение type, а затем использовать условный тип Extract для получения составляющей объединения из Instruction, который имеет тот же тип, что и текущее свойство:

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

...