React TypeScript自定义Hook:指定返回数据至少含id属性的方法
为useFetchData Hook指定返回数据的TypeScript类型约束
要让Hook返回的data数组元素至少包含id: string | number属性,最佳方式是使用泛型+基础类型约束,既保证类型安全,又能适配不同业务场景的扩展需求,具体实现步骤如下:
1. 定义基础约束类型
先声明一个接口,强制要求包含id字段:
interface HasId { id: string | number; }
2. 改造Hook为泛型函数
将原Hook改为泛型函数,让泛型参数继承HasId,以此约束返回数据的结构:
import { useEffect, useState } from "react"; interface HasId { id: string | number; } export const useFetchData = <T extends HasId>( URI: string ): [T[] | null, boolean, string | null] => { const [data, setData] = useState<T[] | null>(null); const [loading, setLoading] = useState<boolean>(true); const [errorMessage, setErrorMessage] = useState<string | null>(null); useEffect(() => { const fetchData = async () => { try { const res = await fetch(URI); // 用类型断言将返回数据转为泛型数组类型 setData(await res.json() as T[]); setTimeout(() => { setLoading(false); }, 2000); } catch (err) { // 优化错误处理,避免非Error类型的异常 setErrorMessage(err instanceof Error ? err.message : "请求发生未知错误"); } }; if (!URI) return; fetchData(); }, [URI]); return [data, loading, errorMessage]; };
3. 使用Hook时指定具体类型
在调用Hook时,传入符合HasId约束的具体业务类型,TypeScript会自动校验并提示类型:
// 示例:定义用户类型,继承HasId interface User extends HasId { name: string; age: number; } // 调用Hook,指定泛型为User const [users, loading, error] = useFetchData<User>("/api/users"); // 此时users的类型为User[] | null,每个元素都包含id、name、age字段,类型完全安全
方案优势
- 灵活性:泛型设计让Hook可以复用在不同接口请求场景,只要返回数据包含id即可
- 类型安全:彻底替代any类型,避免类型丢失和潜在的运行时错误
- 扩展性:业务类型可以在
HasId基础上扩展任意字段,不破坏约束规则
内容的提问来源于stack exchange,提问作者Ben Shekhtman
相关产品推荐
相关产品推荐

