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

TypeScript中useGet自定义Hook的IStatus接口定义问题

自定义useGet Hook的类型优化方案

1. 解决Error类型赋值报错问题

TypeScript中catch捕获的error默认类型是unknown,直接赋值给Error | AxiosError | null类型会触发类型不兼容报错。需要先对error进行类型校验再赋值:

  • 导入AxiosError类型:import axios, { AxiosError } from 'axios'
  • 在catch块中通过instanceof判断error的具体类型,再完成赋值

2. 合理定义data的类型

不要固定设为空数组[],不同接口可能返回对象、数组等不同结构。推荐用泛型让调用者指定返回数据的类型,让Hook具备通用性。

优化后的useGet.ts代码

import { useEffect, useState } from 'react'
import axios, { AxiosError } from 'axios'

// 泛型状态接口,支持自定义data类型
interface IStatus<T> {
  loading: boolean;
  error: null | Error | AxiosError;
  data: null | T;
}

// 泛型Hook,调用时传入返回数据类型
export const useGet = <T>(url: string) => {
  const [status, setStatus] = useState<IStatus<T>>({
    loading: true,
    error: null,
    data: null
  });
  
  useEffect(() => {
    getData();
  }, [url]); // 将url加入依赖,url变化时自动重新请求
  
  const getData = async () => {
    try {
      const res = await axios(url);    
      setStatus({
        loading: false,
        error: null,
        data: res.data
      });
    } catch (error) {
      let typedError: Error | AxiosError | null = null;
      // 精准判断error类型
      if (error instanceof AxiosError) {
        typedError = error;
      } else if (error instanceof Error) {
        typedError = error;
      } else {
        // 兜底处理非Error类型异常
        typedError = new Error(String(error));
      }
      setStatus({
        loading: false,
        error: typedError,
        data: null
      });
      console.error(error);
    }
  }

  // 固定返回值类型,确保调用端类型推断准确
  return [status.data, status.loading, status.error] as const;
}

优化后的Component.tsx代码

import { useGet } from '../hooks/useGet';

const UseGetComponent = () => {
  interface IUser {
    id: number;
    name: string;
    email: string;
  }

  interface IPost {
    id: number;
    userId: number;
    title: string;
  }

  // 调用时指定泛型类型,自动获得类型推断
  const [dataUsers, loadingUsers, errorUsers] = useGet<IUser[]>('https://jsonplaceholder.typicode.com/users')
  const [dataPosts, loadingPosts, errorPosts] = useGet<IPost[]>('https://jsonplaceholder.typicode.com/posts')
  
  return (
    <>
      <h1>Custom hooks</h1>
      {loadingUsers && <div>Loading...</div>}
      {errorUsers && <div>Error: {errorUsers.message}</div>}
      {dataUsers && (
        <div >
          <ul>
            // TypeScript已自动推断user为IUser类型,无需手动指定
            {dataUsers.map((user) => (
              <li key={user.id}>
                {user.name} - {user.email}
                {loadingPosts && <div>Loading...</div>}
                {errorPosts && <div>Error: {errorPosts.message}</div>}
                {dataPosts && (
                  <ul>
                    {dataPosts
                      .filter((post) => post.userId === user.id)
                      .map((post) => (
                        <li key={post.id}>{post.title}</li>
                      ))}
                  </ul>
                )}
              </li>
            ))}
          </ul>
        </div>
      )}
    </>
  )
}

export default UseGetComponent

关键优化点说明

  • 泛型支持:适配不同类型的返回数据,调用端类型推断更准确,无需重复手动指定类型
  • Error类型处理:通过instanceof精准判断异常类型,解决类型不兼容问题,同时兜底处理非标准异常
  • 依赖项修复:将url加入useEffect依赖数组,确保url变更时自动重新请求
  • data类型灵活性:不再固定为数组,由调用者按需指定,适配不同接口的返回结构

内容的提问来源于stack exchange,提问作者sonEtLumiere

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 13:55:21