如何在useFetch自定义Hook中指定响应类型并解决TS类型错误
解决useFetch自定义Hook的TypeScript类型错误
你遇到的错误核心是返回类型与state实际类型不匹配:你定义返回的data类型是ResponseType,但useState初始值为null,导致data的实际类型是ResponseType | null。当ResponseType是不允许为null的类型(比如string、非空接口)时,TypeScript会抛出类型不兼容的错误。
以下是几种可行的解决方案:
方案1:调整返回类型,补充异步状态(推荐)
实际场景中,异步请求存在加载中、请求失败的状态,同时请求完成前data确实是null,直接修改返回类型并补充加载和错误状态,既解决类型问题,也让Hook更实用:
import { useState, useEffect } from 'react'; import axios from 'axios'; function useFetchDemo<ResponseType>(url: string): { data: ResponseType | null; loading: boolean; error: Error | null; } { const [data, setData] = useState<ResponseType | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState<Error | null>(null); useEffect(() => { const fetchData = async () => { try { const res = await axios.get(url); setData(res.data); } catch (err) { setError(err instanceof Error ? err : new Error('请求失败')); } finally { setLoading(false); } }; fetchData(); }, [url]); return { data, loading, error }; }
使用示例:
interface UserInterface { id: number; name: string; } const { data: user, loading, error } = useFetchDemo<UserInterface>("/users/123"); if (loading) return <div>加载中...</div>; if (error) return <div>请求失败:{error.message}</div>; return <div>用户名:{user?.name}</div>;
方案2:传入初始值,保证data始终为ResponseType类型
如果业务上需要data始终是非空的ResponseType,可以让调用者传入符合类型的初始值:
import { useState, useEffect } from 'react'; import axios from 'axios'; function useFetchDemo<ResponseType>(url: string, initialData: ResponseType): { data: ResponseType; } { const [data, setData] = useState<ResponseType>(initialData); useEffect(() => { axios.get(url).then((res) => setData(res.data)); }, [url]); return { data }; }
使用示例:
interface PostInterface { id: number; title: string; } // 传入符合PostInterface的初始值 const { data: post } = useFetchDemo<PostInterface>("/posts/123", { id: 0, title: "" });
方案3:类型断言(不推荐)
如果能保证请求一定会成功且返回数据符合ResponseType,可以用类型断言绕过检查,但这种方法会失去TypeScript的类型安全保障,不建议在生产环境使用:
function useFetchDemo<ResponseType>(url: string): { data: ResponseType; } { const [data, setData] = useState<ResponseType | null>(null); useEffect(() => { axios.get(url).then((res) => setData(res.data)); }, []); // 用类型断言强制转换 return { data: data as ResponseType }; }
内容的提问来源于stack exchange,提问作者user18719885
相关产品推荐
相关产品推荐

