首页 > 解决方案 > Flow中的“强制展开”?

问题描述

我的减速器中有这个辅助函数,它具有给定的状态:

type CustomerCollection = { [number]: Customer }

type CustomerState = {
  +customers: ?CustomerCollection,
  +newItem: ?(Customer | Review),
  +searchResults: ?(Customer[]),
  +error: ?string,
  +isLoading: boolean
};

function customerWithReview(review: Review): Customer {
    const id: number = review.customerId;
    const oldCustomer: Customer = state.customers[id];
    const newReviews: Review[] = [review, ...oldCustomer.reviews];
    return Object.assign(oldCustomer, { reviews: newReviews });
  }

id我在const oldCustomer: Customer = state.customers[id];说的时候得到一个流错误Cannot get state.customers[id] because an index signature declaring the expected key/value type is missing in null or undefined

这是因为?CustomerCollection.state.customers

我可以通过确保customers不为空来消除错误:

 if (state.customers) {
      const oldCustomer: Customer = state.customers[id];
      const newReviews: Review[] = [review, ...oldCustomer.reviews];
      return Object.assign(oldCustomer, { reviews: newReviews });
    }

但随后问题就上链了,因为我没有任何东西可以从函数返回。

我当然可以将其扩展为:

  function customerWithReview(review: Review): Customer {
    if (!state.customers) {
      return new Customer();
    } else {
      const id: number = review.customerId;
      const oldCustomer: Customer = state.customers[id];
      const newReviews: Review[] = [review, ...oldCustomer.reviews];
      return Object.assign(oldCustomer, { reviews: newReviews });
    }
  }

但在实际实践中,将我们带到 reducer 的这个分支的操作​​永远不会被调用 if state.customersis null,而且我们永远不会返回new Customer(),如果我们这样做了,它也没有任何用处。state.customers可以为空,以便区分“我们还没有获取客户 ( state.customers == null)”和“我们已经获取了客户但没有客户 ( state.customers == {})。

如果我可以断言state.customers在这些情况下始终存在,那会容易得多,在 Swift 中我会使用强制展开: const oldCustomer: Customer = state.customers![id];

我可以用 Flow 做这样的事情吗?

或者,考虑到只有我的GET_CUSTOMERS_FAILURE行动才能处理state.customers == null,有没有其他方法可以重组我的减速器,这样会更容易一些?一个完全独立fetchReducer的具有可为空的客户集合,而其余操作属于不同的减速器?

标签: reduxflowtype

解决方案


您可以使用invariant功能(检查它是否在这里工作):

type Customer = { id: number, reviews: Array<Review> };
type Review = { customerId: number };

type CustomerCollection = { [number]: Customer }

type CustomerState = {
  +customers: ?CustomerCollection,
  +newItem: ?(Customer | Review),
  +searchResults: ?(Customer[]),
  +error: ?string,
  +isLoading: boolean
};

declare var state: CustomerState;
declare function invariant(): void;

function customerWithReview(review: Review): Customer {
    const id: number = review.customerId;
    invariant(state.customers, 'No customers and I don\'t know why');
    const oldCustomer: Customer = state.customers[id];
    const newReviews: Review[] = [review, ...oldCustomer.reviews];
    return Object.assign(oldCustomer, { reviews: newReviews });
}

您可以在项目中的某个地方实现它并在必要时导入。

你可以像这样实现它:

export function invariant<T>(value: ?T, falsyErrorMessage: string, errorParams?: Object): void {
  if (!value) {
    log.error(falsyErrorMessage, errorParams || {});
    throw new Error(INVARIANT_ERROR_MESSAGE);
  }
}

不幸的是,函数的名称在流程中是硬编码的。

替代变体只是在您的函数中添加一个if并直接引发错误。customerWithReview


推荐阅读