【问题标题】:How can I write Action for redux action generators?如何为 redux 动作生成器编写动作?
【发布时间】:2021-03-05 04:00:13
【问题描述】:

这些是动作。

export const fetchProductsStart = () => ({
  type: ProductListActionTypes.PRODUCT_LIST_START,
});

export const fetchProductSuccess = (products: IProduct) => ({
  type: ProductListActionTypes.PRODUCT_LIST_SUCCESS,
  payload: products,
});

export const fetchProductFailure = (error: any) => ({
  type: ProductListActionTypes.PRODUCT_LIST_FAILURE,
  payload: error,
});

我是这样写动作的:

export type Action =
  | ReturnType<typeof fetchProductsStart>
  | ReturnType<typeof fetchProductSuccess>
  | ReturnType<typeof fetchProductFailure>;

我把这个传递给reducer的Action类型

 case ProductListActionTypes.PRODUCT_LIST_SUCCESS:
      return { loading: false, products: action.payload };
    case ProductListActionTypes.PRODUCT_LIST_FAILURE:
      return { loading: false, error: action.payload };

我收到了action.payload 的警告。它说“类型动作上不存在属性'有效负载'”

【问题讨论】:

    标签: reactjs typescript redux


    【解决方案1】:

    并非Action 联合中的每个分支都有一个payload 键,并且编译器不知道要采用哪个分支,因为操作的type 被扩大到只是string 而不是 'PRODUCT_LIST_START' | 'PRODUCT_LIST_SUCCESS' | 'PRODUCT_LIST_FAILURE'

    如果您查看Action 的类型,它是

    type Action = {
        type: string;
    } | {
        type: string;
        payload: IProduct;
    } | {
        type: string;
        payload: any;
    }
    

    这是因为ProductListActionTypes被推断为

    const ProductListActionTypes: {
        PRODUCT_LIST_START: string;
        PRODUCT_LIST_SUCCESS: string;
        PRODUCT_LIST_FAILURE: string;
    }
    

    然后编译器无法确定你想要的Action联合的哪个分支,它无法区分它是哪个动作类型,因为类型已扩大到string

    您可以通过在 ProductListActionTypes 声明的末尾添加 as const 来解决此问题。

    export const ProductListActionTypes = {
      PRODUCT_LIST_START: 'PRODUCT_LIST_START',
      PRODUCT_LIST_SUCCESS: 'PRODUCT_LIST_SUCCESS',
      PRODUCT_LIST_FAILURE: 'PRODUCT_LIST_FAILURE'
    } as const;
    

    然后ProductListActionTypes的类型推断为

    const ProductListActionTypes: {
      readonly PRODUCT_LIST_START: "PRODUCT_LIST_START";
      readonly PRODUCT_LIST_SUCCESS: "PRODUCT_LIST_SUCCESS";
      readonly PRODUCT_LIST_FAILURE: "PRODUCT_LIST_FAILURE";
    }
    

    然后Action

    type Action = {
        type: "PRODUCT_LIST_START";
    } | {
        type: "PRODUCT_LIST_SUCCESS";
        payload: IProduct;
    } | {
        type: "PRODUCT_LIST_FAILURE";
        payload: any;
    }
    

    现在编译器知道当你给它一个动作类型时,它会采用Action联合的哪个分支。

    【讨论】:

      【解决方案2】:

      您似乎想使用Discriminated Union。但是 Typescript 假定动作是类型的:

      type Action = {
          type: string;
      } | {
          type: string;
          payload: any;
      } | {
          type: string;
          payload: any;
      }
      

      而且,因此它无法区分switch 语句中的类型。如果我们可以证明type 将是'PRODUCT_LIST_START' | 'PRODUCT_LIST_SUCCESS' | 'PRODUCT_LIST_FAILURE',这将有什么帮助。如果我们可以告诉 Typescript 我们的 ProductListActionTypes 将保持不变,即我们需要 const assert 这个对象。

      我们可以像这样进行常量断言:

      const ProductListActionTypes = {
        PRODUCT_LIST_START: "PRODUCT_LIST_START",
        PRODUCT_LIST_SUCCESS: "PRODUCT_LIST_SUCCESS",
        PRODUCT_LIST_FAILURE: "PRODUCT_LIST_FAILURE",
      } as const;
      

      现在我们的Action 类型看起来像这样:

      type Action = {
          type: "PRODUCT_LIST_START";
      } | {
          type: "PRODUCT_LIST_SUCCESS";
          payload: any;
      } | {
          type: "PRODUCT_LIST_FAILURE";
          payload: any;
      }
      

      而且,你不会看到波浪线。

      See full code at Typescript Playground

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-17
        • 2021-12-18
        • 2015-08-06
        • 2017-04-12
        • 2016-02-18
        相关资源
        最近更新 更多