从Typescript中的联合类型推断回调参数类型的最佳方法是什么?

时间:2019-04-06 19:46:03

标签: typescript typescript-typings typescript-generics

我正在尝试编写一个帮助程序,让我订阅一个React应用程序中特定的 type 分派动作。这些是我正在使用的动作界面:

enum ActionTypes {
  MoveToLine = 'MOVE_TO_LINE',
  MoveToColumn = 'MOVE_TO_COLUMN',
}

interface MoveToLineAction {
  type: ActionTypes.MoveToLine;
  payload: { line: number };
}

interface MoveToColumnAction {
  type: ActionTypes.MoveToColumn;
  payload: { column: number };
}

type Actions = MoveToLineAction | MoveToColumnAction;

这是subscribeToAction的实现:

const subscribeToAction = <A extends { type: string }, T extends ActionTypes>(
  type: T,
  onAction: (a: A) => void,
) => (action: A) => {
  if (action.type === type) {
    onAction(action);
  }
};

我希望能够像这样使用它:

// Subscribe to a specific type of action
subscribeToAction(ActionTypes.MoveToLine, action => {
  action.payload.line;
});

我遇到的问题是我希望自动推断action侦听器中onAction的类型。在上面的代码中,出现Property 'payload' does not exist on type '{ type: string; }'错误。我可以手动键入侦听器来解决此问题:

subscribeToAction(ActionTypes.MoveToLine, (action: MoveToLineAction) => {
  action.payload.line;
});

但是传递ActionType似乎是多余的,然后还必须在侦听器中指定操作类型。你们对如何避免这样做有任何建议吗?

1 个答案:

答案 0 :(得分:1)

这就是我要做的事情:

type ActionOfType<T extends ActionTypes> = Extract<Actions, { type: T }>;

const subscribeToAction = <T extends ActionTypes>(
    type: T,
    onAction: (a: ActionOfType<T>) => void,
) => (action: Actions) => {
    if (action.type === type) {
        // assertion necessary or explicit type guard: 
        onAction(action as ActionOfType<T>);
    }
};

subscribeToAction(ActionTypes.MoveToLine,
    action => { // action inferred as MoveToLineAction
        action.payload.line;
    }
);

您实际上并不需要subscribeToAction()中的两个通用参数。您希望与T组成部分对应的ActionTypes作为type传入,并且您希望onAction回调的参数自动被约束为{{1 }}。 Actions类型的功能说明了如何执行此操作。哦,ActionOfType<T>的返回值应该是接受 any subscribeToAction的函数,对吗?这就是为什么您要进行Actions检查。

还要注意,由于if (action.type === type)的类型为action,因此您需要告诉编译器测试Actions实际上将if (action.type === type)缩小为action。我只是使用类型断言。

好的,希望对您有所帮助。祝你好运!