redux-saga "call" 影响没有正确输入 saga 参数

redux-saga "call" effect not typing saga params correctly

我有一个 saga 定义如下:

type GenericFunction = (...args: any[]) => any;

interface IFetchSaga<T extends GenericFunction> {
  saga: T,
  args: Parameters<T>
}

function* triggerChange<T extends GenericFunction>(fetchSaga: IFetchSaga<T>, shouldFetch: boolean) {
  // ...do stuff
  if(shouldFetch) {
    yield call(fetchSaga.saga, ...fetchSaga.args);
  }
  // ...do stuff
}

当我尝试在另一个传奇中使用这个传奇时,使用 call 效果我没有得到 IFetchSaga args 的正确输入:

function* fetchData(id: number, date: string) {
  // ...do fetch
}

function* load() {
  // ...do stuff
  yield call(triggerChange, {
      saga: fetchData,
      args: ['10', '2021-03-22'] // I don't get an error saying that '10' should be a number
    },
    true
  );
}

例如,当我尝试直接执行它时(就像它是任何其他函数一样),输入正确:

triggerChange({
  saga: fetchData,
  args: ['10', '2021-03-22'] // Here I get the error saying that '10' should be a number
});

在调用我的 saga 时,我能做些什么来正确输入 args 吗?


Ps.: 我知道我可以在调用效果之外定义我的 fetchSaga 参数,但是我必须总是用 [=19= 调用 IFetchSaga ](我想避免它):

function* fetchData(id: number, date: string) {
  // ...do fetch
}

function* load() {
  // ...do stuff
  // This would work, but I want to avoid having to do it 
  const fetchSaga: IFetchSaga<typeof fetchData> = {
    saga: fetchData,
    args: ['10', '2021-03-22'] // Get the typing error for '10'
  };

  yield call(triggerChange, fetchSaga, true);
}

解决方案

我的建议是通过辅助函数创建 IFetchSaga<T> 对象。

function fetchable<T extends GenericFunction>( saga: T, ...args: Parameters<T>): IFetchSaga<T> {
  return {saga, args};
}

如果需要,您可以将参数作为数组传递。

这允许 typescript 轻松推断函数的正确参数并确保它们匹配。

function* load() {
  // error: Argument of type 'string' is not assignable to parameter of type 'number'
  yield call(triggerChange, fetchable(fetchData, "10", "2021-03-22"), true);
  // okay :)
  yield call(triggerChange, fetchable(fetchData, 10, "2021-03-22"), true);
}

问题

原始版本失败的原因与 相似,我在其中进行了更深入的探讨。 triggerChange 是一个通用函数,可以用任何 T 调用。当我们为 triggerChange 创建 call 效果时,它不需要任何特定的 T 类型,因为 T 是在调用函数时确定的。参数的类型回落到 GenericFunction,其中 argsany[],因此将数组分配给它没有问题。

我们的解决方案有效,因为我们通过直接调用 fetchable 来推断特定的 T。给我们错误的是 fetchable 函数,而不是 call。如果我们要声明 fetchable T 只是 GenericFunction 那么我们将遇到与以前相同的问题。

// no errors, even though we want them
yield call(triggerChange, fetchable<GenericFunction>(fetchData, "10", "2021-03-22"), true);