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

如何为React自定义useApi Hook指定返回数据类型解决TS报错

解决方案

核心是给useApi增加TypeScript泛型支持,让调用时可以动态传入返回数据和请求参数的类型,具体改造步骤如下:

1. 改造useApi.tsx

给Hook添加两个泛型参数:TData 定义接口返回的数据类型,TParams 定义请求入参的类型,同时补全useEffect依赖项避免逻辑bug:

import { AxiosResponse, AxiosPromise } from 'axios';
import { useState, useEffect } from 'react';

// 定义泛型:TData为返回数据类型,TParams为请求参数类型
const useApi = <TData = unknown, TParams = Record<string, unknown>>(
    apiFunction: (params: TParams) => Promise<AxiosResponse<TData>>,
    params: TParams = {} as TParams,
    callback?: (data: TData) => void
): [boolean, TData | null, null | string] => {
    const [data, setData] = useState<TData | null>(null);
    const [isLoading, setIsLoading] = useState(true);
    const [error, setError] = useState<null | string>(null);

    useEffect(() => {
        apiFunction(params)
            .then(({ data }: AxiosResponse<TData>) => {
                setData(data);
                setIsLoading(false);
                callback?.(data);
            })
            .catch(() => {
                setError('Something went wrong');
                setIsLoading(false);
            });
    // 补全依赖项,参数变化时自动重新请求
    }, [apiFunction, params, callback]);

    return [isLoading, data, error];
};

export default useApi;

2. 改造getMovie请求函数

修正返回类型,支持泛型传入返回数据类型:

import axios, { AxiosResponse } from "axios";
type getMovieParams = { _id: string };
const BASE_URL = "https://jsonplaceholder.typicode.com/todos/";
// 添加泛型T指定返回数据类型
const getMovie = <T,>(params: getMovieParams): Promise<AxiosResponse<T>> => {
  if (params) {
    const { _id } = params;
    if (_id) {
      const url = `${BASE_URL}/${_id}`;
      return axios.get<T, AxiosResponse<T>>(url);
    }
  }
  throw new Error("Must provide a query");
};

export default getMovie;

3. 组件内调用时指定泛型

调用useApi时传入你定义的Movie接口作为返回数据类型,同时调整渲染逻辑避免类型冲突:

import "./styles.css";
import useApi from "./useApi";
import getMovie from "./api";
interface Movie {
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}

export default function App() {
  const idMovie = { _id: "3" };
  // 回调函数参数类型直接指定为Movie
  const someAction = (data: Movie) => {
    // 执行业务逻辑
    return data;
  };

  // 调用时传入泛型:第一个是返回数据类型,第二个是请求参数类型
  const [isLoading, data, error] = useApi<Movie, {_id: string}>(getMovie, idMovie, someAction);

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>{error}</div>;
  }

  // 走到这里时error不存在,data一定是Movie类型,不会有类型报错
  return (
    <div>
      -- 获取电影数据1 --
      <p>{data.title}</p>
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 13:18:04