ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

@tanstack/preact-query DefinedUseInfiniteQueryResult:理解 initialData 场景下「永不 undefined」的无限查询结果类型

2026/9/9 12:31:22 拓冰建站 浏览量
@tanstack/preact-query DefinedUseInfiniteQueryResult:理解 initialData 场景下「永不 undefined」的无限查询结果类型 tanstack/preact-query DefinedUseInfiniteQueryResult理解 initialData 场景下「永不 undefined」的无限查询结果类型【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/queryDefinedUseInfiniteQueryResult 是 preact-query 包中useInfiniteQuery在设置initialData时返回的结果类型别名其核心承诺是只要配置了initialData返回结果的data就永远不会是undefined因此渲染层可以放心直接访问data.pages与data.pageParams。本文将从类型定义、源码重载机制、底层状态机联合类型与实际编码模式四个层面完整拆解这一 API 类型帮助你理解 preact-query 无限查询类型系统的设计逻辑。一、类型定义一行别名背后的含义DefinedUseInfiniteQueryResult的全部定义仅有一行——它是tanstack/query-core中DefinedInfiniteQueryObserverResult的直接再导出re-exporttype DefinedUseInfiniteQueryResultTData, TError DefinedInfiniteQueryObserverResultTData, TError;该定义位于 packages/preact-query/src/types.ts#L376-L379配套的 JSDoc 说明如下它是useInfiniteQuery在设置initialData时的返回值类型在该场景下data永远不会是undefined它直接再导出tanstack/query-core的DefinedInfiniteQueryObserverResult。preact-query 之所以要定义一个“本地”类型别名是为了让框架层的公共 API 表面稳定用户只面向tanstack/preact-query导出见 packages/preact-query/src/index.ts 的导出清单而底层复用query-core的类型即可保证不同框架适配层之间类型行为完全一致。二、类型参数解析原文档为两个类型参数给出了明确含义参数默认值语义TDataunknown当配置了select变换后data最终呈现的类型默认即缓存中查询数据的类型TErrorDefaultErrorqueryFn分页请求函数可能抛出的错误类型对于无限查询data并非单页数据而是形如InfiniteDataTQueryFnData的聚合结构。在 packages/query-core/src/types.ts#L210-L213 中可看到它的标准形态export interface InfiniteDataTData, TPageParam unknown { pages: ArrayTData pageParams: ArrayTPageParam }因此若未显式传入selectTData在无限查询里会进一步收敛为InfiniteDataTQueryFnData每页数据类型 每页对应的 pageParam 列表。需要特别留意select变换既可能改变TDataInfiniteData的变换也可能在极少数场景把它变换成别的形状类型参数保持开放正为此设计。三、它何时被返回useInfiniteQuery 的重载选择机制只看别名本身无法回答“为什么 data 不会 undefined”关键在于useInfiniteQuery的重载overload设计。查看 packages/preact-query/src/useInfiniteQuery.ts#L64-L79函数暴露了首个重载export function useInfiniteQuery TQueryFnData, TError DefaultError, TData InfiniteDataTQueryFnData, TQueryKey extends QueryKey QueryKey, TPageParam unknown, ( options: DefinedInitialDataInfiniteOptions TQueryFnData, TError, TData, TQueryKey, TPageParam , queryClient?: QueryClient, ): DefinedUseInfiniteQueryResultTData, TErrorTypeScript 会自动依据传入 options 是否包含initialData来选择重载当 options 是 DefinedInitialDataInfiniteOptions即已设置initialData时返回类型被收窄为DefinedUseInfiniteQueryResult否则走第二个重载返回的是 UseInfiniteQueryResult其中data在查询pending期间可能是undefined。也就是说“data 是否可能为 undefined”这一个信息被编码进了options 类型 → 返回类型的类型级映射中这正是 TanStack Query 类型系统里很典型的“输入配置决定输出状态”设计。DefinedInitialDataInfiniteOptions对initialData的约束在 packages/preact-query/src/infiniteQueryOptions.ts#L104-L128 中体现export type DefinedInitialDataInfiniteOptions... UseInfiniteQueryOptions... { initialData: | NonUndefinedGuardInfiniteDataTQueryFnData, TPageParam | (() NonUndefinedGuardInfiniteDataTQueryFnData, TPageParam) | undefined }即该分支要求initialData是**完整的InfiniteData含pages与pageParams**或其惰性工厂函数——这保证了缓存中从一开始就有可读数据。四、底层展开DefinedInfiniteQueryObserverResult 的联合类型再往深处走DefinedUseInfiniteQueryResult本质上是query-core中DefinedInfiniteQueryObserverResult的别名。在 packages/query-core/src/types.ts#L1051-L1056 中可见其真实结构export type DefinedInfiniteQueryObserverResult TData unknown, TError DefaultError, | InfiniteQueryObserverRefetchErrorResultTData, TError | InfiniteQueryObserverSuccessResultTData, TError而完整的 InfiniteQueryObserverResult 则是export type InfiniteQueryObserverResult... | DefinedInfiniteQueryObserverResultTData, TError // success refetchError | InfiniteQueryObserverLoadingErrorResultTData, TError // data: undefined | InfiniteQueryObserverLoadingResultTData, TError // data: undefined | InfiniteQueryObserverPendingResultTData, TError // data: undefined | InfiniteQueryObserverPlaceholderResultTData, TError // placeholder 数据对比可以得出关键结论Defined...含Defined前缀版本从结果联合中去掉了pending、loading、loadingError三个data: undefined的分支也去掉了placeholderplaceholderData分支只保留InfiniteQueryObserverSuccessResultstatus: success、data: TData、error: nullInfiniteQueryObserverRefetchErrorResult后台重新拉取失败但data仍然有值data: TData、status: error。因此无论当前是成功态还是“带着旧数据重新拉取失败”的错误态data都必然已定义也就允许渲染层不再写data?.pages之类的空值防御。这一点可以从 useInfiniteQuery.ts#L38-L62 的官方示例中得到印证——设置initialData后可直接渲染data.pages同时在错误分支并行展示错误信息即便 refetch 失败列表也不会消失import { useInfiniteQuery } from tanstack/preact-query function Projects() { const { data, isError, error } useInfiniteQuery({ queryKey: [projects], queryFn: ({ pageParam }) fetchProjects(pageParam), initialPageParam: 0, getNextPageParam: (lastPage) lastPage.nextId, initialData: { pages: [], pageParams: [] }, }) return ( div {isError ? spanError: {error.message}/span : null} ul {data.pages.map((page) page.projects.map((p) li key{p.id}{p.name}/li), )} /ul /div ) }五、Defined 结果仍保有的无限查询专属字段即便data保证有值作为无限查询结果它依旧继承InfiniteQueryObserverBaseResult中所有分页专用成员这些字段定义于 packages/query-core/src/types.ts#L904-L944字段类型要点说明data.pages/data.pageParamsArrayTData/ArrayTPageParam已拉取的全部页数据与对应参数fetchNextPage(options?)返回 Promise拉取下一页fetchPreviousPage(options?)返回 Promise拉取上一页hasNextPage/hasPreviousPageboolean是否还有下一/上一页依据getNextPageParam/getPreviousPageParam推断isFetchingNextPage/isFetchingPreviousPageboolean正在拉取下一/上一页isFetchNextPageError/isFetchPreviousPageErrorboolean拉取下一/上一页失败需要注意的是DefinedUseInfiniteQueryResult只携带TData、TError两个泛型参数而页面数据与页码类型已固化在TData的InfiniteData结构中所以 API 表面比UseInfiniteQueryOptions还含TQueryFnData、TPageParam更简洁。六、与相邻类型的对照搞清四个 Result 的取舍在 packages/preact-query/src/types.ts 中无限查询结果相关类型共有四个容易混淆特此整理类型触发场景data是否可能为undefined定义位置UseInfiniteQueryResultuseInfiniteQuery未设置initialData是pending/loading期间types.ts#L364-L367DefinedUseInfiniteQueryResultuseInfiniteQuery设置了initialData否types.ts#L376-L379UseSuspenseInfiniteQueryResultuseSuspenseInfiniteQuery否Suspense 成功前不渲染types.ts#L388-L394DefinedUseQueryResult非无限useQuery设置initialData或 Suspense 查询否types.ts#L352-L355其中UseSuspenseInfiniteQueryResult等于DefinedInfiniteQueryObserverResult再OmitKeyof掉isPlaceholderDataSuspense 永不渲染占位数据见 types.ts#L381-L394 的注释。而同步普通查询对应的DefinedUseQueryResult与无限版本同构仅数据形态为单值而非InfiniteData。七、使用实践initialData 的语义与注意事项DefinedUseInfiniteQueryResult的一切保证都源于initialData因此理解它的语义边界有助于正确使用该类型初始数据可做种子列表最常见的写法是initialData: { pages: [], pageParams: [] }空页列表配合“加载更多”按钮实现首屏即渲染骨架、点击后逐页追加的效果。initialData 会写入缓存源码注释infiniteQueryOptions.ts#L117-L128明确说明initialData会被持久化到查询缓存而placeholderData不会——这是两者最本质的区别。初始数据默认视为 stale除非显式设置staleTime否则只要数据被配置为 initialData 注入就认为它已过期挂载后仍会触发一次后台刷新。若希望首屏“先用缓存立即渲染、后台静默更新”可参考 guides/important-defaults.md 与 guides/initial-query-data.md 的约定配置staleTime。惰性初始化initialData也可以传函数该函数会在查询共享初始化期间仅执行一次且要求同步返回数据见 infiniteQueryOptions.ts#L38-L51 中关于InitialDataFunction的说明。小心命令式拉取与自动 refetch 的相互干扰useInfiniteQuery的 JSDoc 特别提示useInfiniteQuery.ts#L27-L29fetchNextPage这类命令式调用可能干扰默认的 refetch 行为导致页面数据与最新状态不一致建议只在响应用户操作时调用或追加hasNextPage !isFetching之类的守卫条件。与queryClient.infiniteQuery共享 optionsinfiniteQueryOptions({...})返回携带类型推断的 options 对象可在useInfiniteQuery与命令式 API 间复用见 infiniteQueryOptions.ts#L147-L159 与 docs/framework/preact/reference/functions/useInfiniteQuery.md。// 守卫式“加载更多”按钮data 类型为 DefinedUseInfiniteQueryResult const { data, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage } useInfiniteQuery({ queryKey: [projects], queryFn: ({ pageParam }) fetchProjects(pageParam), initialPageParam: 0, getNextPageParam: (lastPage) lastPage.nextId, initialData: { pages: [], pageParams: [] }, }) button onClick{() fetchNextPage()} disabled{!hasNextPage || isFetching} {isFetchingNextPage ? Loading more... : hasNextPage ? Load More : Nothing more to load} /button八、进一步阅读在仓库中可继续深入验证的关联资料DefinedUseInfiniteQueryResult 原始类型文档本文对应的 API 参考条目UseInfiniteQueryResult 类型别名 与 UseSuspenseInfiniteQueryResult 类型别名同一组 API 的对照类型DefinedUseQueryResult 类型别名普通查询场景的对应版本无限查询实践指南包含分页、无限滚动等完整用法初始查询数据指南 与 重要默认值指南解释initialData与staleTime的默认行为源码类型别名 packages/preact-query/src/types.ts、重载签名 packages/preact-query/src/useInfiniteQuery.ts、options 构造 packages/preact-query/src/infiniteQueryOptions.ts、底层联合类型 packages/query-core/src/types.ts。总结DefinedUseInfiniteQueryResult不是一行可有可无的语法糖它把“有initialData→data恒有值”这一运行时事实固化进了静态类型系统配合底层DefinedInfiniteQueryObserverResult对错误/成功状态的联合收窄让开发者可以在初始化数据已就绪的场景中写出更简洁、零空值防御的无限查询渲染代码。【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/query创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考