Javascript redux 操作缺少流联合类型 属性

Javascript flow union types missing property for redux action

我正在尝试学习如何使用 Flow,但我被困在这里。

我有一个接受不同类型操作的 redux reducer。每个动作的动作负载都不同,例如:

const CreateNewTaskAction = (n: number) => {
    return {type: "CREATE", payload: n};
}

const AnotherAction = (r: TaskHandlerType) => {
    return {type: "WHATEVER", payload: r}
}

动作负载的类型如下:

type TaskHandlerType = {
    ...
    childId: number,
    parentId: number,
}                                                       


export type ActionType = {                                                       
    type: string,                                                                
    payload?: string | number | TaskHandlerType,
}         

这是我的减速器的一部分:

const MyReducer = (state: StateType, action: ActionType) = {
    switch(action.type) {
        ...
        case "WHATEVER":
            ....
            var newChildrenArray = oldChildrenArray.filter((el) => {   
                return el != action.payload.childId;                   
            })                                                         
            ....

        }
    }

这是 Flow 吐出的错误:

Cannot get action.payload.childId because:
 • property childId is missing in String [1].
 • property childId is missing in undefined [2].
 • property childId is missing in Number [3].

              src/redux/reducers/tasksReducer.js
              57│             var oldChildrenArray = state[parentId].childrenIds
              58│             var elementIndex = oldChildrenArray.indexOf(action.payload)
              59│             var newChildrenArray = oldChildrenArray.filter((el) => {
              60│                 return el != action.payload.childId;
              61│             })
              62│             var newParentState = {
              63│                 ...state[parentId],

              src/redux/actions/actionType.js
 [1][2][3] 17│     payload?: string | number | TaskHandlerType ,

它正在检查操作负载是字符串或数字的情况,并警告这些类型没有 属性 childId,但这就是我在该分支上使用 switch 语句的原因,action.payload 将始终具有 childId。

那我怎么告诉 Flow 呢?

编辑我刚刚注意到你的减速器正在开启action.payload。也许应该改为打开 action.type OP 评论说这只是问题中的错字。

Flow 在推断 payload 的类型时遇到问题,因为它主要关心 action 参数的类型(表示 payload?: string | number | TaskHandlerType),而不是值的具体形状你路过。

原因是:如果您添加 另一个具有相同类型但负载形状不同的 操作会发生什么情况?此操作可能如下所示:

{
  type: 'WHATEVER',
  payload: "foo"
}

并且 Flow 想要确保您的 reducer 能够处理它,因为根据 TaskHandlerType 此操作是有效的。 当然不会这样做,因为 Redux 操作 type 必须是唯一的,但 Flow 不知道这一点。

基本上,有一个假设 - 只能用特定的 type 定义一个动作,并且其 payload 的形状将始终相同 - 这对 Flow 是不可见的。我 认为 Flow 没有任何内置功能可以直接表达这一点......但是,幸运的是,还有另一种方法可以解决这个问题(尽管有更多样板)。

您可以使用 union type(类似于 payloadTaskHandlerType 中的类型)来告诉 Flow 每个特定消息的确切形状。一种方法如下:

// Actions

type CreateNewTaskActionType = {| type: "CREATE", payload: number |};
const CreateNewTaskAction = (n: number): CreateNewTaskActionType => ({
    type: "CREATE",
    payload: n
});

type AnotherActionType = {| type: "WHATEVER", payload: TaskHandlerType |};
const AnotherAction = (r: TaskHandlerType): AnotherActionType => ({
    type: "WHATEVER",
    payload: r
});

// Types

type ActionType = CreateNewTaskActionType | AnotherActionType;

现在,Flow 可以知道具有 type: "WHATEVER" 的值保证具有 payload 类型的 TaskHandlerType

Interactive demo

希望对您有所帮助,如有其他问题欢迎评论!