在TypeScript中的switch语句中为具有常量枚举和推断类型的接口编制索引

在TypeScript中的switch语句中为具有常量枚举和推断类型的接口编制索引,typescript,enums,switch-statement,type-inference,Typescript,Enums,Switch Statement,Type Inference,我试图根据满足case条件的enum值,自动推断在switch语句中传递的某些数据的类型 为了实现这一点,我定义了一个常量枚举: const enum MESSAGES { open = 1, close, redo } 然后我用它来索引接口: interface MessagePayloadContent { [MESSAGES.open]: string; [MESSAGES.close]: number; [MESSAGES.redo]: boolean; }

我试图根据满足
case
条件的
enum
值,自动推断在
switch
语句中传递的某些数据的类型

为了实现这一点,我定义了一个常量枚举:

const enum MESSAGES {
  open = 1,
  close,
  redo
}
然后我用它来索引
接口

interface MessagePayloadContent {
  [MESSAGES.open]: string;
  [MESSAGES.close]: number;
  [MESSAGES.redo]: boolean;
}
此时,我定义了将在
switch
语句中计算的对象:

interface MessagePayload<T extends MESSAGES> {
  scope: T;
  content: MessagePayloadContent[T];
}

我不完全明白的是,在其他一些情况下,这确实有效,因此我想知道为什么在其他一些情况下它不起作用。

这里的问题是,
MessagePayload
类型不是您认为的类型。接口通常不分布在联合体上,因此其计算结果仅为:

interface OopsMessagePayload {
  scope: MESSAGES;
  content: string | number | boolean;
}
这意味着如果您检查
范围
属性,它不会缩小
内容
属性的类型

TypeScript确实有一些分布在联合体上的类型级构造,因此应该有一种方法来定义

type MessagePayloadDistributive<T> = ...
如果检查该值,
SomeMessagePayload
将计算为上述所需类型。然后,以下代码将按预期工作:

function pick(payload: SomeMessagePayload): void {
  switch (payload.scope) {
    case MESSAGES.open:
      open(payload.content); // okay
      break;
    case MESSAGES.close:
      close(payload.content); // okay
      break;
    case MESSAGES.redo:
      redo(payload.content); // okay
      break;
  }
}
好的,希望能有帮助。祝你好运

MessagePayloadDistributive<MESSAGES> 
MessagePayload<MESSAGES.open> |
MessagePayload<MESSAGES.closed> |
MessagePayload<MESSAGES.redo> 
type MessagePayloadDistributive<T extends MESSAGES> = T extends any
  ? MessagePayload<T>
  : never;

type SomeMessagePayload = MessagePayloadDistributive<MESSAGES>;
function pick(payload: SomeMessagePayload): void {
  switch (payload.scope) {
    case MESSAGES.open:
      open(payload.content); // okay
      break;
    case MESSAGES.close:
      close(payload.content); // okay
      break;
    case MESSAGES.redo:
      redo(payload.content); // okay
      break;
  }
}