使用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
相关产品推荐
相关产品推荐

