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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 18:18:28