如何为自定义useFetch Hook自动推断数据类型?
解决useRequest Hook的类型约束问题
要避免使用any类型同时支持任意返回数据结构,**泛型(Generics)**是最佳方案。通过给Hook添加泛型参数,你可以让调用方指定返回数据的类型,TypeScript会自动完成类型检查和推导。
修改后的代码示例:
import { useState } from 'react'; import { AxiosError } from 'axios'; // 定义请求方法类型(如果之前未定义) type Method = 'GET' | 'POST' | 'PUT' | 'DELETE'; // 添加两个泛型参数:D表示请求参数类型,T表示响应数据类型 function useRequest<D = unknown, T = unknown>(url: string, method: Method, data: D) { // 将response的类型从any改为T | undefined const [response, setResponse] = useState<T | undefined>(undefined); const [isLoading, setIsLoading] = useState<boolean>(false); const [error, setError] = useState<AxiosError | undefined>(undefined); const requestNow = async () => { setIsLoading(true); setError(undefined); try { // 根据请求方法调用对应apiClient方法,并指定泛型T约束响应数据 let apiResponse; switch (method) { case 'POST': apiResponse = await apiClient.post<T>(url, data); break; case 'GET': apiResponse = await apiClient.get<T>(url, { params: data }); break; // 可根据需要扩展其他请求方法 default: throw new Error(`Unsupported method: ${method}`); } // apiResponse.data会被自动推断为T类型 setResponse(apiResponse.data); } catch (err) { setError(err as AxiosError); } finally { setIsLoading(false); } }; return { response, isLoading, error, requestNow }; }
使用示例
调用Hook时传入具体类型,TypeScript会自动校验并提供类型提示:
// 定义业务数据类型 interface User { id: number; name: string; email: string; } // 调用useRequest,指定请求参数和响应数据类型 const { response, isLoading, error, requestNow } = useRequest<{ userId: number }, User>( '/api/user', 'POST', { userId: 123 } ); // 此时response被推断为User | undefined,访问属性时有类型校验 if (response) { console.log(response.name); // 类型合法,有代码提示 }
关键说明
- 泛型参数
D和T分别约束请求参数、响应数据的类型,默认值设为unknown比any更安全——unknown需要显式类型断言才能使用,避免隐式类型漏洞 - 调用axios方法时指定泛型
<T>,确保返回的data属性符合预期类型 - Hook本身无需修改,调用方可以根据业务需求传入任意合法类型,兼顾灵活性和类型安全
内容的提问来源于stack exchange,提问作者DevOverflow
相关产品推荐
相关产品推荐

