使用 Typescript 在 Redux-Saga 中键入生成器函数

IT技术 reactjs typescript redux redux-saga
2021-05-13 23:51:24

最近我开始重构我的 React 项目以开始在其中使用 Typescript。我遇到了打字问题,我不知道如何克服。

技术栈:Typescript、React、Redux、Redux-Saga

我也在使用带有 AirBnB 规则集的 ESLint。

我正在尝试编写一个使用在我的授权服务中定义的异步函数的传奇。下面的代码是我第二次尝试写这个。我已经拆分signIn传奇,以便不按照本文末尾的建议混合收益返回类型

export function* callSignInService(userCredentials: UserCredentialsInterface): 
    Generator<CallEffect, UserAuthDataInterface, UserAuthDataInterface> > 
{
    return yield call(signInService, userCredentials);
}

export function* signIn(action: PayloadAction<UserCredentialsInterface>): 
    Generator<StrictEffect, void, PutEffect> 
{
    try {
        const { payload } = action;
        const userData = yield* callSignInService(payload);

        yield put(signInSuccess(userData));
    } catch (error) {
        yield put(signInFailure(error.message));
    }
}

登录服务的简化版本:

const signIn = async ( userCredentials: UserCredentialsInterface ): Promise<UserAuthDataInterface>
{
    /* ... Some credential format validations ... */
    try {
        const response = await axios.post('someUrl', userCredentials);
        return {
            /* objectContent */
        }: UserAuthDataInterface
    } catch (error) {
        throw new Error(AuthorizationErrorType.SERVER_ERROR);
    }    
}

问题是我仍然收到以下错误:

const userData = yield* callSignInService(payload);

说:

TS2766:无法将迭代委托给值,因为其迭代器的“next”方法需要“UserAuthDataInterface”类型,但包含的生成器将始终发送“PutEffect”。类型 'SimpleEffect<"PUT", PutEffectDescriptor>' 缺少来自类型 'UserAuthDataInterface' 的以下属性:用户、令牌

我知道问题在于我的登录生成器NextType设置为PutEffect并且它期望表达式yield signInService(userCredentials)返回PutEffect但这不是我的目标。我想使用signInService来获取UserAuthData ,然后将这些数据放入signInSuccess操作(signInSuccess是使用操作创建者创建的)。

我已经阅读了一些关于如何正确键入生成器的资源,但仍然无法在我的示例中使用它。我发现 redux-saga 在打字方面有问题或有问题,但我不确定 2021 年是否仍然如此。

我在这里错过了一些明显的东西吗?也许我尝试编写这样的 Saga 存在问题。如果有人可以看看并给我一个如何处理这个问题的建议,我会很高兴。

1个回答

第一个泛型类型参数是yieldsaga 中 ed 值的类型换句话说,就是“步骤”。

移动callSignInService到一个单独的函数实际上对类型没有帮助,因为我们仍然在yield处理那个结果。

您的signInsaga 有两个不同类型的步骤——调用 API 和调度操作。泛型需要是两种类型的联合。

export function* signIn(
  action: PayloadAction<UserCredentialsInterface>
): Generator<
  // step types
  CallEffect<UserAuthDataInterface> | PutEffect<AnyAction>,
  // return type
  void,
  // intermediate argument
  UserAuthDataInterface
> {
  try {
    const { payload } = action;
    const userData: UserAuthDataInterface = yield call(signInService, payload);

    yield put(signInSuccess(userData));
  } catch (error) {
    yield put(signInFailure(error.message));
  }
}

我假设您的设置需要返回类型声明(否则这很容易!)。暂时删除声明以查看 Typescript 推断的内容真的很有帮助。我就是这样得到这个解决方案的。