Svelte Query 的 CreateQueryResult 类型:createQuery 返回值结构、状态机与 TypeScript 类型推导完全指南
发布时间:2026/9/11 3:03:53来源:尧图网络
Svelte Query 的 CreateQueryResult 类型createQuery 返回值结构、状态机与 TypeScript 类型推导完全指南【免费下载链接】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/queryCreateQueryResultTData, TError是 TanStack Query 为 Svelte 封装层tanstack/svelte-query定义的查询结果类型它描述createQuery的每一次返回值包含status/fetchStatus双状态、data/error载荷以及一系列派生布尔标志。本文将以其定义packages/svelte-query/src/types.ts#L47-L51为骨架深入 Svelte 源码与 query-core 类型层讲清它的别名来源、泛型参数含义、底层结果联合类型、initialData对类型的收窄效果以及如何在实际 Svelte 组件中正确消费这些字段——读完你就能熟练用类型安全的方式处理加载、成功、失败三种查询状态。一、CreateQueryResult 的类型定义与定位在 packages/svelte-query/src/types.ts 中CreateQueryResult是一个极简的类型别名/** Result from createQuery */ export type CreateQueryResult TData unknown, TError DefaultError, CreateBaseQueryResultTData, TError而CreateBaseQueryResult同样只是一层转发同文件第 33-37 行/** Result from createBaseQuery */ export type CreateBaseQueryResult TData unknown, TError DefaultError, QueryObserverResultTData, TError也就是说Svelte 封装层自身没有定义新的结果结构而是把类型责任完全委托给了 query-core 的QueryObserverResult。CreateQueryResult的存在意义在于提供语义化命名明确这是createQuery的返回值与createInfiniteQuery的CreateInfiniteQueryResult、createMutation的CreateMutationResult同文件第 69-72、139-144 行区分开作为公开 API 的稳定类型出口让组件、工具函数可以显式标注查询结果的类型而不需要直接依赖 query-core 的内部类型名。类型参数TData 与 TErrorCreateQueryResult接受两个泛型参数均有默认值类型参数默认值含义TDataunknown查询成功后data字段的实际数据类型即queryFn解析值经select转换后的类型TErrorDefaultError查询失败时error字段的错误类型DefaultError是 query-core 的默认错误类型通常是Error值得注意的是TData的默认值是unknown而非TQueryFnData——在createQuery的签名中TData默认继承TQueryFnData见 packages/svelte-query/src/createQuery.ts#L74-L84此时TData会被精确推断为queryFn的返回类型。但如果手动标注结果类型时没有传入TData它就会退回到unknown需要访问data前先收窄。二、底层真相QueryObserverResult 联合类型与结果状态机要真正用好CreateQueryResult必须理解它的底层别名QueryObserverResult。该类型定义在 packages/query-core/src/types.ts#L897-L902export type QueryObserverResultTData unknown, TError DefaultError | DefinedQueryObserverResultTData, TError | QueryObserverLoadingErrorResultTData, TError | QueryObserverLoadingResultTData, TError | QueryObserverPendingResultTData, TError | QueryObserverPlaceholderResultTData, TError这是一个可辨识联合discriminated union每种成员都通过字面量status字段区分。五个分支分别是联合成员statusdataerror关键标志QueryObserverPendingResultpendingundefinednullisPending: trueQueryObserverLoadingResultpendingundefinednullisPending: true、isLoading: trueQueryObserverLoadingErrorResulterrorundefinedTErrorisLoadingError: trueQueryObserverRefetchErrorResulterrorTDataTErrorisRefetchError: trueQueryObserverSuccessResultsuccessTDatanullisSuccess: trueQueryObserverPlaceholderResultsuccessTDatanullisPlaceholderData: true注意QueryObserverLoadingResult与QueryObserverPendingResult的status都是pending区别在于isLoading前者代表首次加载进行中后者是禁用/未开始状态。这也是 createQuery 文档中反复强调禁用查询用isLoading而非isPending判断的原因。status 与 fetchStatus 双状态模型从 packages/query-core/src/types.ts#L664-L665 可以看到 query-core 定义了双状态export type QueryStatus pending | error | success export type FetchStatus fetching | paused | idlestatusQueryStatus表示数据层面的状态是否有可用数据、上次尝试是否失败fetchStatusFetchStatus表示请求层面的状态queryFn是否正在执行fetching、是否因网络模式被暂停paused或空闲idle。两者组合才能完整描述一个查询例如有旧数据 后台刷新中对应status: successfetchStatus: fetchingisRefetching为true离线暂停对应fetchStatus: pausedisPaused为true。三、CreateBaseQueryResult 的完整字段清单QueryObserverBaseResultpackages/query-core/src/types.ts#L667-L793为所有联合成员提供了公共字段。这是CreateQueryResult实际携带的全部运行时信息按用途分类如下数据与错误载荷字段类型说明dataTData \| undefined最后一次成功解析的数据不同联合分支中被收窄为undefined或TDataerrorTError \| null查询抛出的错误对象默认nulldataUpdatedAtnumberstatus最近一次变为success的时间戳errorUpdatedAtnumberstatus最近一次变为error的时间戳errorUpdateCountnumber所有错误的累计次数failureCountnumber失败次数每次失败 1成功时重置为0failureReasonTError \| null用于重试决策的失败原因成功时重置为null派生布尔标志字段等价关系说明isPendingstatus pending无缓存数据且无已完成请求isErrorstatus error查询尝试出错isSuccessstatus success成功拿到数据可渲染isLoadingisFetching isPending首次请求在途不含禁用状态isFetchingfetchStatus fetching任何请求在途含后台刷新isRefetchingisFetching !isPending后台刷新在途isLoadingError—首次加载即失败无旧数据isRefetchError—已有数据时刷新失败isPlaceholderData—当前展示的是 placeholder 数据isPausedfetchStatus paused想请求但被暂停isStale—缓存被失效或超过staleTimeisFetched—查询已被抓取过isFetchedAfterMount—组件挂载后是否抓取过可用于屏蔽旧缓存isEnabled—观察者是否启用isInitialLoading—已废弃改用isLoading状态与操作status: QueryStatus——数据层状态pending | error | successfetchStatus: FetchStatus——请求层状态fetching | paused | idlerefetch(options?)——手动重新抓取返回PromiseQueryObserverResultTData, TError支持cancelRefetch等选项见 packages/query-core/src/types.ts#L774-L776。四、源码链路CreateQueryResult 是如何被生产出来的理解类型后再看运行时这条结果是如何诞生的。createQuery的实现packages/svelte-query/src/createQuery.ts#L258-L263极为简洁export function createQuery(options, queryClient?) { return createBaseQuery(options, QueryObserver, queryClient) }它把工作委托给createBaseQuerypackages/svelte-query/src/createBaseQuery.svelte.ts核心流程为解析客户端$derived(useQueryClient(queryClient?.()))——默认从最近上下文取QueryClient默认化选项client.defaultQueryOptions(options())合并默认配置并根据isRestoring设置_optimisticResults创建观察者new QueryObserver(client, resolvedOptions)并在客户端变化时重建生成结果observer.getOptimisticResult(resolvedOptions)获得乐观结果再通过observer.trackResult(result)跟踪属性访问以实现细粒度响应式更新订阅同步$effect中observer.subscribe(() update(createResult()))观察者每次通知都重新计算结果。由于 Svelte 5 的 runes 机制$derived、$state、$effectoptions被设计为AccessorT即() T函数以实现响应式——选项变化时watchChanges会调用observer.setOptions(resolvedOptions)触发重新计算。返回值就是类型为CreateQueryResultTData, TError的响应式结果。测试印证真实字段行为packages/svelte-query/tests/createQuery/Base.svelte 是官方测试夹具直接消费createQuery的返回值把status、fetchStatus、data、isFetched、isStale、isFetching、isSuccess、isPlaceholderData等字段渲染到 DOM 供断言同目录测试用例如createQuery.svelte.test.ts验证了isLoading/isPending/isLoadingError/isPlaceholderData等标志在加载、成功、错误各阶段的组合取值。这说明上述字段不仅是类型声明更是经测试验证的运行时契约。五、泛型推导与 initialData 的类型收窄CreateQueryResult有一个关键类型行为当且仅当传入initialData时结果类型会被收窄为DefinedCreateQueryResult此时data不再是TData | undefined而是保证存在的TData。createQuery在 packages/svelte-query/src/createQuery.ts 中提供了三个重载// 重载 1未设置 initialData function createQueryTQueryFnData, TError, TData, TQueryKey( options: AccessorUndefinedInitialDataOptions..., queryClient?: AccessorQueryClient, ): CreateQueryResultTData, TError // 重载 2设置了 initialData —— 返回 DefinedCreateQueryResult function createQueryTQueryFnData, TError, TData, TQueryKey( options: AccessorDefinedInitialDataOptions..., queryClient?: AccessorQueryClient, ): DefinedCreateQueryResultTData, TError // 重载 3通用支持 select 等 function createQueryTQueryFnData, TError, TData, TQueryKey( options: AccessorCreateQueryOptions..., queryClient?: AccessorQueryClient, ): CreateQueryResultTData, TErrorDefinedCreateQueryResult的定义在 packages/svelte-query/src/types.ts#L87-L90export type DefinedCreateQueryResult TData unknown, TError DefaultError, DefinedCreateBaseQueryResultTData, TError它最终对应 query-core 的DefinedQueryObserverResultpackages/query-core/src/types.ts#L890-L895只包含QueryObserverRefetchErrorResult和QueryObserverSuccessResult两个分支——data在这两个分支中都是TData。类型层面还保证了status永远不会是pending有initialData就有数据可展示因此模板中可以不写 loading 分支。对应的DefinedInitialDataOptions/UndefinedInitialDataOptions类型定义在 packages/svelte-query/src/queryOptions.ts#L10-L28。实践价值当你在组件里写下createQuery(() ({ queryKey: [posts], queryFn: fetchPosts, initialData: [] }))时TypeScript 自动选择重载 2query.data被推断为非空数组{each query.data as post}无需空值保护而未传initialData时data保持TData | undefined模板需要先通过status/isPending分支收窄。六、在 Svelte 组件中消费 CreateQueryResult以下用法全部来自 createQuery 官方文档示例docs/framework/svelte/reference/functions/createQuery.md与源码 JSDoc 示例packages/svelte-query/src/createQuery.ts可直接复制运行。1. 通过 status 分支渲染三态script langts import { createQuery } from tanstack/svelte-query const query createQuery(() ({ queryKey: [posts], queryFn: fetchPosts, })) /script {#if query.status pending} Loading... {:else if query.status error} spanError: {query.error.message}/span {:else} ul {#each query.data as post (post.id)} li{post.title}/li {/each} /ul {/if}这里status联合类型让 TS 自动收窄error分支中query.error可用success分支中query.data是Post[]。2. 使用派生布尔标志isPending/isSuccess/isError与status完全等价选择可读性更好的写法{#if query.isPending} Loading... {:else if query.isError} spanError: {query.error.message}/span {:else} ul {#each query.data as post (post.id)} li{post.title}/li {/each} /ul {/if}3. initialData 收窄类型、避免 loading 闪烁script langts import { createQuery } from tanstack/svelte-query // data 是 Post[]绝不可能是 undefined —— 即使刷新失败 // 列表仍会与错误信息一起展示status 不会进入 pending const query createQuery(() ({ queryKey: [posts], queryFn: fetchPosts, initialData: [], })) /script {#if query.isError} spanError: {query.error.message}/span {/if} ul {#each query.data as post (post.id)} li{post.title}/li {/each} /ul4. select 派生 data不改动缓存select会在缓存值之上派生组件所需的数据缓存中仍是完整Post[]但query.data的类型变为numberscript langts import { createQuery } from tanstack/svelte-query const query createQuery(() ({ queryKey: [posts], queryFn: fetchPosts, select: (posts) posts.length, })) /script {#if query.isPending} Loading... {:else if query.isError} spanError: {query.error.message}/span {:else} span{query.data} posts/span {/if}5. 禁用查询用 isLoading 而非 isPendingenabled: false时status为pending但不应显示 loading。isLoading isFetching isPending禁用状态下两者皆假script langts import { createQuery } from tanstack/svelte-query let { postId }: { postId: number | undefined } $props() const query createQuery(() ({ queryKey: [post, postId], queryFn: () fetchPost(postId!), enabled: postId ! null, })) /script {#if postId null} Select a post {:else if query.isLoading} Loading... {:else if query.isError} spanError: {query.error.message}/span {:else} h1{query.data?.title}/h1 {/if}6. 用缓存列表为详情查询做 initialData 种子从已缓存的列表查询中寻找详情数据作为initialData跳过详情页的加载态script langts import { createQuery, useQueryClient } from tanstack/svelte-query let { postId }: { postId: number } $props() const queryClient useQueryClient() const query createQuery(() ({ queryKey: [post, postId], queryFn: () fetchPost(postId), initialData: () queryClient .getQueryDataArrayPost([posts]) ?.find((post) post.id postId), })) /script {#if query.isError} spanError: {query.error.message}/span {/if} h1{query.data?.title}/h17. placeholderData 与 isPlaceholderData翻页时保留旧数据分页查询中placeholderData: keepPreviousData让上一页数据在下一页加载期间继续可见isPlaceholderData用于禁用按钮script langts import { createQuery, keepPreviousData } from tanstack/svelte-query let page $state(0) const query createQuery(() ({ queryKey: [posts, page], queryFn: () fetchPosts(page), placeholderData: keepPreviousData, })) /script {#if query.isError} spanError: {query.error.message}/span {/if} ul {#each query.data ?? [] as post (post.id)} li{post.title}/li {/each} /ul button disabled{query.isPlaceholderData} onclick{() page} Next Page /button七、与其他结果类型的对应关系CreateQueryResult不是孤立存在的——types.ts中还定义了一组姊妹类型便于按查询形态选择正确的结果类型Svelte 封装类型对应核心类型适用场景CreateBaseQueryResultQueryObserverResultcreateBaseQuery的通用结果CreateQueryResultQueryObserverResultcreateQuery的结果DefinedCreateQueryResultDefinedQueryObserverResultcreateQuery且设置了initialDataCreateInfiniteQueryResultInfiniteQueryObserverResultcreateInfiniteQuery的结果DefinedCreateInfiniteQueryResultDefinedInfiniteQueryObserverResultcreateInfiniteQuery且设置了initialDataCreateMutationResultMutationObserverResult含重写的mutate/mutateAsynccreateMutation的结果例如createInfiniteQuery返回CreateInfiniteQueryResultTData, TErrorpackages/svelte-query/src/types.ts#L69-L72其底层InfiniteQueryObserverBaseResult在QueryObserverBaseResult基础上额外增加了data页数组、hasNextPage/hasPreviousPage、fetchNextPage/fetchPreviousPage、isFetchingNextPage/isFetchingPreviousPage等分页字段。八、实战排查结果字段不符合预期时的检查清单当你发现query的某个字段行为异常时按以下顺序排查确认响应式写法createQuery的 options 必须是Accessor() ({...})而不是普通对象——Svelte 5 下才能追踪响应式依赖见 packages/svelte-query/src/createBaseQuery.svelte.ts 中的watchChanges机制区分 status 与 fetchStatusisPending看数据层isFetching看请求层有旧数据在刷新时status success但isFetching true禁用查询enabled: false时不要用isPending判断 loading用isLoading手动 refetchquery.refetch()返回 Promise可用await获取刷新后的结果配合cancelRefetch: false可避免取消在途请求见 packages/svelte-query/tests/createQuery/Base.svelte 中的按钮绑定类型收窄失效确认是否传了initialData若用queryOptions工厂共享配置注意queryOptions也会保留initialData的类型标记packages/svelte-query/src/queryOptions.ts。结语CreateQueryResultTData, TError虽然只是一行类型别名但它连接着 Svelte 响应式层与 query-core 的完整查询状态机。掌握它的联合分支结构pending/error/success×fetching/paused/idle、字段语义与initialData收窄规则你就能写出类型安全、状态判断准确的 Svelte Query 组件——无论是简单列表、依赖查询、分页还是乐观 UI都能基于这一份结果契约从容实现。【免费下载链接】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),仅供参考
网站建设高端定制企业官网