如何键入多个收益生成器(redux-saga)

How to type multiple yield generator (redux-saga)

我们的 redux-saga 生成器包含多个 yield 语句,return 不同的结果。 我需要帮助正确输入它们。

这是一个例子:

const addBusiness = function* addBusiness(action: AddBusinessActionReturnType): Generator<
  Promise<Business> | SelectEffect | PutEffect<{ payload?: ActionPayload<Array<Business>>; type: string }>,
  void,
  Business | BusinessesContainer
> {
    const { url, showToast = true } = action.payload;

    const businessDetails: Business = yield Network.get<Business>( // ts error: Type 'Business | BusinessesContainer' is not assignable to type 'Business'.

      `businesses?url=${url}`,
    );

    if (showToast) {
      const getBusinessesFromState = (state: AppState) => ({
        ...state.business.businesses,
      });
      const businesses: BusinessesContainer = yield select(getBusinessesFromState); // ts error: Type 'Business | BusinessesContainer' is not assignable to type 'BusinessesContainer'
      onAddBusinessSuccessToast(businesses, businessDetails);
    }

    yield put({ // ts error: Type 'SimpleEffect<"PUT", PutEffectDescriptor<{ type: string; payload: Business[]; }>>' is not assignable to type 'SelectEffect'
      type: constants.SAVE_BUSINESS_REQUEST,
      payload: [businessDetails],
    });

在上面的评论中,您可以看到我们得到的 ts 错误。 任何帮助,将不胜感激。 谢谢

看来你肯定是犯了一些过度打字的错误。当然 yield Network.get<Business>() return 是 Business 对吧?如果您分配给它的值是 Business.

,则不必写 const businessDetails: Business

这些生成器 return 类型可能真的很难正确输入,但 Typescript 足够聪明,可以找出正确的类型。您可以完全关闭它,这样会很好。如果您很难找出正确的类型,您可以暂时删除 return 类型以查看推断的类型是什么。这就是我如何解决您的第一个问题,即联合 Business | BusinessesContainer 需要更改为交集 Business & BusinessesContainer.

我不知道 ActionPayload 类型是什么,但似乎没有必要。您将 put 操作的负载输入为 ActionPayload<Array<Business>>,但 Array<Business> 本身是正确的。当您始终提供 payload 时,没有理由将其设为可选。

这两项更改暂时解决了您的打字稿问题……。我经常看到 API 调用在 call effect 中执行,这会使类型更加复杂。但我不确定 call 是否真的需要。

const addBusiness = function* addBusiness(action: AddBusinessActionReturnType): Generator<
  Promise<Business> | SelectEffect | PutEffect<{ payload: Array<Business>; type: string }>,
  void,
  Business & BusinessesContainer
> {
    const { url, showToast = true } = action.payload;

    const businessDetails: Business = yield Network.get<Business>( `businesses?url=${url}` );

    if (showToast) {
      const getBusinessesFromState = (state: AppState) => ({
        ...state.business.businesses,
      });
      const businesses: BusinessesContainer = yield select(getBusinessesFromState);
      onAddBusinessSuccessToast(businesses, businessDetails);
    }

    yield put({
      type: "SAVE_BUSINESS_REQUEST",
      payload: [businessDetails],
    });
  }

// dummy types that I filled in to check types

type Business = {
  name: string;
  id: number;
}

type BusinessesContainer = {
  businesses: Business[];
}

const Network = {
  get: async <T>(url: string): Promise<T> => {
    return {} as unknown as T;
  }
}

type AddBusinessActionReturnType = {
  type: string;
  payload: {
    showToast?: boolean;
    url: string;
  }
}

type AppState = {
  business: {
    businesses: BusinessesContainer;
  }
}

const onAddBusinessSuccessToast = (businesses: BusinessesContainer, businessDetails: Business) => undefined;