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

如何移除React Query InfiniteQuery中pageParam的额外类型检查

移除TanStack React Query InfiniteQuery中的pageParam类型检查方案

我在用TanStack React Query实现InfiniteQuery时,必须额外检查pageParam的number类型才能正常运行,现在希望在不改变现有文件结构的前提下简化代码,移除以下类型检查逻辑,求可行的重构方案:

queryFn: ({pageParam}) => {
    if (typeof pageParam === 'number') return UseTodoService.getAll(pageParam);
    else throw new Error("pageParam must be a number.");
},

现有代码文件如下:

ApiClient.ts

import axios from "axios";

const apiClient = axios.create({
    baseURL: 'https://jsonplaceholder.typicode.com/'
})

class API<T> {
    constructor(public endpoint: string) {
    }

    getAll = (pageParam: number) => {
       return apiClient.get<T[]>(this.endpoint, {
            params: {
                _page: pageParam
            }
        }).then(res => res.data)
            .catch(err => err)
    }
}

export default API

todo-service.ts

import API from "../api-service/api-client.ts";

export interface Todo {
    userId: number;
    id: number;
    title: string;
    completed: boolean;
}
const UseTodoService = new API<Todo>('todos')

export default UseTodoService;

useTodo hook

import {useInfiniteQuery} from "@tanstack/react-query";
import {CACHE_KEY_TODO} from "../constants.ts";
import UseTodoService, {Todo} from "../http-service/todo-service.ts";

const UseTodo = () => {
   return useInfiniteQuery<Todo[], Error>({
       queryKey: CACHE_KEY_TODO,
       queryFn: ({pageParam}) => {
           if (typeof pageParam === 'number') return UseTodoService.getAll(pageParam);
           else throw new Error("pageParam must be a number.");
       },
       getNextPageParam: (lastPage, allPages) =>
           lastPage.length > 0 ? allPages.length + 1 : undefined,
       initialPageParam: 1
   })
    }

export default UseTodo;

Todo component

import useTodo from "../hooks/useTodo.ts";

function TodoList() {
    const {data, fetchNextPage } = useTodo()
    return <>
        <h1>TodoList</h1>
        <ul className="list-group">
            {data?.pages.map(todos => todos.map((todo, index) =>
                <li className="list-group-item" key={index}>{todo.title}</li>))}
        </ul>
        <button onClick={() => fetchNextPage()} className="btn btn-primary mt-2">Fetch More</button>
    </>
}

export default TodoList;

重构方案:利用TypeScript泛型强化类型约束

核心思路是通过TypeScript的泛型明确useInfiniteQuery中pageParam的类型,让编译期完成类型校验,彻底消除运行时的类型检查逻辑。

修改useTodo hook的代码,补充useInfiniteQuery的完整泛型参数,指定pageParam为number类型:

import {useInfiniteQuery} from "@tanstack/react-query";
import {CACHE_KEY_TODO} from "../constants.ts";
import UseTodoService, {Todo} from "../http-service/todo-service.ts";

const UseTodo = () => {
   return useInfiniteQuery<Todo[], Error, Todo[], number>({
       queryKey: CACHE_KEY_TODO,
       queryFn: ({pageParam}) => UseTodoService.getAll(pageParam),
       getNextPageParam: (lastPage, allPages) =>
           lastPage.length > 0 ? allPages.length + 1 : undefined,
       initialPageParam: 1
   })
}

export default UseTodo;

方案说明:

  1. useInfiniteQuery的泛型参数顺序为:QueryData, Error, PageData, PageParam,显式指定PageParam为number后,TypeScript会自动约束pageParam的类型。
  2. 你的initialPageParam是1(number类型),getNextPageParam返回值要么是allPages.length + 1(number)要么是undefined,完全符合类型约束,编译期就能确保pageParam不会出现非number值。
  3. 移除运行时类型检查后,代码更简洁,同时类型安全由TypeScript编译期保障,不会丢失原有校验能力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:55:18