如何从类型映射中推断类型

时间:2019-03-29 14:49:02

标签: typescript generics types typeguards

我不知道如何在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 个答案:

答案 0 :(得分:1)

您可以实现Type Guard文档enter link description here

但是首先您必须声明事件的并集:

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将在if语句中更改ev的类型。

完整示例:

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

Playground

答案 1 :(得分:1)

你在这里...

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

Demo

我知道有一个可以接受的答案,但这无疑是更好的答案,因为...

  1. 没有运行时开销(这意味着不会在将要执行的编译代码中添加任何内容)
  2. 更好的BetEvent类型,因为它很好地结合了所有可能的事件类型(悬停以查看我在说什么)

您应该考虑将此标记为接受