自定义 React 挂钩在 useReducer 状态值上接收打字稿错误

Custom React hook receiving typescript error on useReducer state value

我正在尝试用 typescript 编写一个 fetch helper hook。我在下面的代码中收到一个打字稿错误,我不知道如何修复。

import * as React from 'react';

const INITIAL_STATE = {data: undefined, loading: false, error: undefined};
const ACTIONS = {
  LOADING: 'LOADING',
  ERROR: 'ERROR',
  DONE: 'DONE',
};
interface UseApiFetch<DataType> {
  data?: DataType;
  error: any;
  loading: boolean;
}
interface Action<DataType> {
  type: string;
  error?: any;
  data?: DataType;
}
const reducer = <DataType>(
  state: UseApiFetch<DataType>,
  {type, error, data}: Action<DataType>
): UseApiFetch<DataType> => {
  switch (type) {
    case ACTIONS.LOADING:
      return {...INITIAL_STATE, loading: true};
    case ACTIONS.ERROR:
      return {...INITIAL_STATE, error};
    case ACTIONS.DONE:
      return {...INITIAL_STATE, data};
    default:
      return state;
  }
};

const useApiFetch = <DataType>(
  fetcher: (...args: any[]) => Promise<any>,
  ...params: any[]
): UseApiFetch<DataType> => {
  const [state, dispatch] = React.useReducer(reducer, INITIAL_STATE);
  React.useEffect(() => {
    if (fetcher) {
      dispatch({type: ACTIONS.LOADING});
      fetcher(...params)
        .then((data) => dispatch({type: ACTIONS.DONE, data}))
        .catch((error) => dispatch({type: ACTIONS.ERROR, error}));
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [fetcher, ...params]);
  /*
   Error occurs here:
   Type 'UseApiFetch<unknown>' is not assignable to type 'UseApiFetch<DataType>'.
     Type 'unknown' is not assignable to type 'DataType'.
      'DataType' could be instantiated with an arbitrary type which could be unrelated to 'unknown'.
  */
  return state;
};

export default useApiFetch;

// in another file I call it like this
function myFetcherFunction(
  userId: number
): Promise<MyFetcherReturnType> {
  return client.api('myRequest', userId);
}
const {data, error, loading} = useApiFetch<MyFetcherReturnType>(myFetcherFunction, userId);

我认为您需要向 useReducer 添加类型。

const [state, dispatch] = React.useReducer<
    (
      state: UseApiFetch<DataType>,
      action: Action<DataType>
    ) => UseApiFetch<DataType>
  >(reducer, INITIAL_STATE)

type参数定义reducer函数的类型。如果没有这种类型,TypeScript 将尝试从 reducer 推断类型,但由于 reducer 是一个通用函数,TypeScript(或可能是 React)将状态类型推断为 UseApiFetch<unknown>,因为它不能键入一个值通用类型 UseApiFetch<T>.

理想情况下,您可以在这里重用现有类型的减速器(类似于 typeof reducer<DataType>),但我还没有找到实现该目标的方法。