You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用useReducer与泛型时无法推断类型T,初始数据类型为unknown

解决React自定义Hook useFetchOnMount的泛型类型推断问题

问题场景

开发React自定义Hook useFetchOnMount 时,结合useReducer与泛型<T>定义状态结构,将initialData的类型指定为T,但TypeScript却将其推断为unknown,导致initialData无法正确匹配泛型指定的类型。

相关代码如下:

import { useEffect, useReducer } from "react";

type Action<T> =
  | { type: "FETCH_INIT" }
  | { type: "FETCH_FAIL" }
  | { type: "FETCH_SUCCESS"; data: T };

interface FetchState<T> {
  isLoading: boolean;
  isError: boolean;
  data: T;
}

function fetchDataReducer<T>(
  state: FetchState<T>,
  action: Action<T>
): FetchState<T> {
 switch (action.type) {
    case "FETCH_INIT":
      return { ...state, isLoading: true, isError: false };

    case "FETCH_FAIL":
      return { ...state, isLoading: false, isError: true };

    case "FETCH_SUCCESS":
      return { ...state, isLoading: false, isError: false, data: action.data };

    default:
      return { ...state };
 }
}

export default function useFetchOnMount<T>(
  url: string,
  initialData: T
): FetchState<T> {
  const [state, dispatch] = useReducer(fetchDataReducer, {
    isLoading: true,
    isError: false,
    data: initialData,
  });

  useEffect(() => {
    let didCancel = false;

    async function fetchData() {
      dispatch({ type: "FETCH_INIT" });
      try {
        const response = await fetch(url, {
          method: "GET",
        });

        if (!response.ok) {
          dispatch({ type: "FETCH_FAIL" });
        }

        const data = await response.json();
        if (!didCancel && response.ok) {
          dispatch({ type: "FETCH_SUCCESS", data: data });
        }
      } catch (error) {
        if (!didCancel) {
          dispatch({ type: "FETCH_FAIL" });
        }
      }
    }

    fetchData();

    return () => {
      didCancel = true;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  return state;
}

问题原因

useReducer无法自动从传入的初始state推断出fetchDataReducer的泛型参数,导致TypeScript无法将initialData的类型T与reducer的泛型关联起来,最终将data的类型推断为unknown。

解决方案

有两种方式可以让TypeScript正确识别泛型类型:

方案一:给fetchDataReducer显式指定泛型参数

在调用useReducer时,给fetchDataReducer加上泛型<T>,明确告知TypeScript当前reducer使用的泛型类型:

const [state, dispatch] = useReducer(fetchDataReducer<T>, {
  isLoading: true,
  isError: false,
  data: initialData,
});

方案二:给初始state指定FetchState<T>类型

先定义初始state并显式标记其类型为FetchState<T>,再传入useReducer:

const initialState: FetchState<T> = {
  isLoading: true,
  isError: false,
  data: initialData,
};
const [state, dispatch] = useReducer(fetchDataReducer, initialState);

额外优化:处理response.json()的类型

response.json()默认返回unknown类型,在FETCH_SUCCESS中dispatch时会存在类型不匹配的风险,建议通过类型断言将其转换为泛型T:

const data = await response.json() as T;

内容的提问来源于stack exchange,提问作者numuno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 06:25:04