typescript 记录和歧视性工会准入

rjee0c15  于 2023-01-06  发布在  TypeScript
关注(0)|答案(1)|浏览(155)

我想让react reducer函数更加通用,并将动作处理程序分离成函数。

export type Actions =
  | {
  type: "ADD_COLUMN";
  newColumnIndex: number;
  column: SelectorColumnData;
}
  | {
  type: "ITEM_CHECKED";
  columnIndex: number;
  item: SelectorItem;
};

export type ActionTypes = Actions["type"];
// type ActionTypes = "ADD_COLUMN" | "ITEM_CHECKED";

这对我来说很有意义:

const reducerRecord: Record<ActionTypes, (draft: Draft<SelectorState>, action: Actions) => void> = {
  "ITEM_CHECKED": itemCheckedAction,
  "ADD_COLUMN": addColumnAction,
};

export const selectorReducer: ImmerReducer<SelectorState, Actions> = (
  draft: Draft<SelectorState>,
  action: Actions,
): void => {
  reducerRecord[action.type](draft, action);
};

我的动作处理程序:

export const itemCheckedAction = (draft: Draft<SelectorState>, action: Actions) => {
  const { columnIndex, item } = action;
  // ...
}

TypeScript不喜欢这个(TS2339: property 'columnIndex' does not exist on type 'Actions'),所以我尝试了这个:

export const itemCheckedAction = (draft: Draft<SelectorState>, action: Actions) => {
  const { columnIndex, item }: Extract<Actions, { type: "ITEM_CHECKED" }> = action;
  // ...
}

也不喜欢这个!它说“ADD_COLUMN”类型丢失了。
奇怪的是,如果我写:

export const itemCheckedAction = (draft: Draft<SelectorState>, action: Actions) => {
  if(action.type === "ITEM_CHECKED") {
    const { columnIndex, item }: Actions = action;
  }
  // ...
}

...将鼠标悬停在= action上会显示所需的联合子类型,但IDE仍然抱怨columnIndexitem不是Actions的属性。
有什么想法吗?

pes8fvy9

pes8fvy91#

您需要强制参数进行区分。最简单的方法是将其与目标type变量相交:

export type Actions =
  | {
  type: "ADD_COLUMN";
  newColumnIndex: number;
  column: never;
}
  | {
  type: "ITEM_CHECKED";
  columnIndex: number;
  item: never;
};

export type ActionTypes = Actions["type"];

export const itemCheckedAction = (draft: never, action: Actions & { type: "ITEM_CHECKED" }) => {
  const { columnIndex, item } = action;
  // ...
}

TypeScriptPlayground链接

相关问题