Как вывести тип из карты типов - PullRequest
0 голосов
/ 29 марта 2019

Я не могу понять, как обеспечить безопасность типов в функции onEvent.

enum MyEnum {
  One,
  Two
}

type Payloads = {
  [MyEnum.One]: { iAmOne: string; one: number };
  [MyEnum.Two]: { iAmTwo: string; two: number };
};

interface BetEvent<ENUM extends MyEnum> {
  type: ENUM;
  payload: Payloads[ENUM];
}

const onEvent = (ev: BetEvent<any>) => {
  if (ev.type === MyEnum.Two) {
    ev.type; // should be MyEnum.Two
    ev.payload; // should be { iAmTwo: string; two: number };
    ev.payload.iAmOne; // should throw Error
  }
};

Ответы [ 2 ]

1 голос
/ 30 марта 2019

Вот, пожалуйста ...

enum BetEventType {
  One,
  Two
}

type BetPayloads = {
  [BetEventType.One]: { iAmOne: string; one: number };
  [BetEventType.Two]: { iAmTwo: string; two: number };
};

type BetEvent = {
  [T in BetEventType]: {
    type: T,
    payload: BetPayloads[T]
  }
}[BetEventType]

const onEvent = (ev: BetEvent) => {
  if (ev.type === BetEventType.Two) {
    ev.type; // is BetEventType.Two
    ev.payload; // is { iAmTwo: string; two: number };
    ev.payload.iAmOne; // gives compile error
  }
};

Демо

Я знаю, что есть принятый ответ, но этот, несомненно, лучше, потому что ...

  1. Нет накладных расходов времени выполнения (имеется в виду отсутствие добавления в скомпилированный код, который будет выполняться)
  2. Лучше BetEvent типа, потому что это хороший союз всех возможных типов событий (наведите курсор, чтобы увидеть, о чем я говорю)

Вы должны пометить это как принятое

1 голос
/ 29 марта 2019

Вы можете реализовать Type Guard docs введите описание ссылки здесь

Но сначала вы должны объявить объединение событий:

type Events = BetEvent<MyEnum.One> | BetEvent<MyEnum.Two>; 

Тогда давайте объявим охрану:

let enumTwoGuard = (ev: Events): ev is BetEvent<MyEnum.Two> => ev.type === MyEnum.Two;

Синтаксис ev is BetEvent<MyEnum.Two> означает, что TS изменит тип ev в операторе if.

Полный пример:

const onEvent = (ev: BetEvent<any>) => {
  if (enumTwoGuard(ev)) {
    ev.type; // BetEvent<MyEnum.Two>.type: MyEnum.Two
    ev.payload; // { iAmTwo: string; two: number; }
    ev.payload.iAmOne; // ERROR
  }
};

Детская площадка

...