【问题标题】:What's the best way to infer the callback argument type from a union type in Typescript?从 Typescript 中的联合类型推断回调参数类型的最佳方法是什么?
【发布时间】:2019-08-28 09:19:49
【问题描述】:

我正在尝试编写一个帮助程序,让我订阅 React 应用程序中调度操作的特定类型。这些是我正在使用的操作界面:

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

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

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

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

【问题讨论】:

    标签: typescript typescript-typings typescript-generics


    【解决方案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 对应于作为type 传入的ActionTypes 成分,并且您希望onAction 回调的参数自动约束到Actions 的相应成分。 ActionOfType&lt;T&gt; 类型函数显示了如何做到这一点。哦,subscribeToAction 的返回值应该是一个接受 any Actions 的函数,对吧?这就是您进行if (action.type === type) 检查的原因。

    还要注意,因为actionActions 类型,所以您需要告诉编译器测试if (action.type === type) 实际上将action 缩小到ActionOfType&lt;T&gt;。我只是使用类型断言。

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

    【讨论】:

    • 谢谢,这看起来像我要找的。不知道Extract。我会试一试。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    • 2022-08-03
    • 2023-03-15
    • 2021-04-09
    相关资源
    最近更新 更多