TanStack Query Svelte 的 DefinedCreateQueryResult 类型:理解 createQuery 与 initialData 的非空数据契约
TanStack Query Svelte 的 DefinedCreateQueryResult 类型理解 createQuery 与 initialData 的非空数据契约【免费下载链接】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导读本文聚焦 Svelte 生态下 TanStack Querytanstack/svelte-query暴露的一个关键类型别名——DefinedCreateQueryResult。它定义了createQuery在提供initialData时返回结果的 TypeScript 类型形状其核心价值在于一旦查询配置了初始数据编译器就能保证data永远不为undefined从而在模板中省去繁琐的空值分支判断。读完本文你将掌握该类型的定义来源、类型参数语义、它与DefinedQueryObserverResult的继承关系以及它在createQuery、queryOptions、createQueries中如何影响类型推断并能结合类型测试理解其行为边界。类型定义一行别名背后的三层契约DefinedCreateQueryResult的定义极其精简完整声明位于 packages/svelte-query/src/types.ts:87-90/** Options for createQuery with initialData */ export type DefinedCreateQueryResult TData unknown, TError DefaultError, DefinedCreateBaseQueryResultTData, TError它本身是DefinedCreateBaseQueryResult的别名而后者同文件 packages/svelte-query/src/types.ts:80-84又指向tanstack/query-core中导出的DefinedQueryObserverResult/** Options for createBaseQuery with initialData */ export type DefinedCreateBaseQueryResult TData unknown, TError DefaultError, DefinedQueryObserverResultTData, TError追踪到核心层 packages/query-core/src/types.ts:890-902可以看到最终的真身是一个联合类型export type DefinedQueryObserverResult TData unknown, TError DefaultError, | QueryObserverRefetchErrorResultTData, TError | QueryObserverSuccessResultTData, TError export type QueryObserverResultTData unknown, TError DefaultError | DefinedQueryObserverResultTData, TError | QueryObserverLoadingErrorResultTData, TError | QueryObserverLoadingResultTData, TError | QueryObserverPendingResultTData, TError | QueryObserverPlaceholderResultTData, TError从源码结构可以清晰看到整个继承链DefinedCreateQueryResultTData, TError └── DefinedCreateBaseQueryResultTData, TError (svelte-query/src/types.ts) └── DefinedQueryObserverResultTData, TError (query-core/src/types.ts) ├── QueryObserverRefetchErrorResult └── QueryObserverSuccessResult这条链的核心语义是「Defined」意味着结果中只可能处于success或「重取失败但数据仍在」两种状态。对照普通QueryObserverResult还包含pending、loading、loadingError、placeholder等状态DefinedQueryObserverResult明确排除了数据缺失的一切可能性——因为initialData保证了查询从一开始就有数据可用。类型参数TData 与 TError 的默认值与含义与原文档一致DefinedCreateQueryResult接受两个类型参数参数默认值含义TDataunknown查询成功后或使用initialData/select转换后的数据类型。在Defined场景下data字段的类型就是TData本身而非TData \| undefinedTErrorDefaultError错误对象类型默认取tanstack/query-core中的DefaultError通常为Error可通过throwOnError配置推导细化TData在createQuery的签名中通常由TQueryFnData或select函数返回值推导而来详见 packages/svelte-query/src/createQuery.ts:74-84而TError默认即DefaultError导入自tanstack/query-core见 packages/svelte-query/src/types.ts:3。何时触发 Defined 结果initialData 驱动的重载选择DefinedCreateQueryResult并非总是createQuery的返回类型——它只在配置了initialData时被启用。这通过createQuery的函数重载实现packages/svelte-query/src/createQuery.ts:74-132无initialData重载参数类型为UndefinedInitialDataOptions返回CreateQueryResultTData, TError此时data的类型包含undefined有initialData重载参数类型为DefinedInitialDataOptions返回DefinedCreateQueryResultTData, TError此时data恒为TData。两个选项类型定义在 packages/svelte-query/src/queryOptions.ts:10-28export type UndefinedInitialDataOptions... CreateQueryOptions... { initialData?: undefined | InitialDataFunctionNonUndefinedGuardTQueryFnData } export type DefinedInitialDataOptions... CreateQueryOptions... { initialData: | NonUndefinedGuardTQueryFnData | (() NonUndefinedGuardTQueryFnData) }注意DefinedInitialDataOptions中的initialData是必填的且其类型为NonUndefinedGuardTQueryFnData即排除了undefined的类型可以是静态值或惰性函数。这意味着传入对象字面量initialData: { wow: true }→ 走 Defined 重载data类型为{ wow: true }传入返回undefined的函数initialData: () undefined→ 会被收窄到UndefinedInitialDataOptions重载data类型仍包含undefined完全不传initialData→CreateQueryResultdata为TData | undefined。这种设计让「是否有初始数据」这一运行时事实直接映射为编译期的类型事实避免模板中对data做不必要的空值断言。类型参数部分提供的语法糖queryOptions 的等价路径同样的 Defined/Undefined 二分也被queryOptions采用packages/svelte-query/src/queryOptions.ts:68-121。它有两个重载传入DefinedInitialDataOptions时返回带数据标签QueryKeyWithDataTag的DefinedInitialDataOptions传入UndefinedInitialDataOptions时返回对应的UndefinedInitialDataOptions。因此把带initialData的选项放进queryOptions再传给createQuery依然能拿到DefinedCreateQueryResult的非空数据保证script langts import { createQuery, queryOptions } from tanstack/svelte-query const postsOptions queryOptions({ queryKey: [posts], queryFn: fetchPosts, initialData: [], // 必须提供否则退回 CreateQueryResult }) const query createQuery(() postsOptions) /script {#if query.isError} spanError: {query.error.message}/span {/if} ul {#each query.data as post (post.id)} li{post.title}/li {/each} /ulcreateQueries 中的 Defined 推断逻辑createQueries同样遵循「有initialData则返回 Defined 结果」的规则。其内部通过条件类型GetDefinedOrUndefinedQueryResult做推断packages/svelte-query/src/createQueries.svelte.ts:78-93核心逻辑可概括为若选项不含initialData→CreateQueryResult若initialData类型为unknown未显式提供→CreateQueryResult若initialData的值类型可赋给TData→DefinedCreateQueryResult若initialData是函数则递归检查其返回类型——只有返回类型非undefined且可赋给TData时才返回DefinedCreateQueryResult否则回落为CreateQueryResult。这一步与createQuery的重载行为保持严格一致函数形式的initialData只有在确定不会返回undefined时才能兑现非空数据契约。类型测试验证行为即契约仓库中的类型测试直接固化了上述行为是理解该类型最权威的旁证。packages/svelte-query/tests/createQuery/createQuery.test-d.ts:6-50 中覆盖了四种典型场景以对象形式提供initialData: { wow: true }→expectTypeOf(data).toEqualTypeOf{ wow: boolean }()不含undefined通过queryOptions传递同样成立未提供initialData→data类型为{ wow: boolean } | undefined提供initialData: () undefined as { wow: boolean } | undefined函数可返回undefined→ 回落为{ wow: boolean } | undefined。这些断言证明DefinedCreateQueryResult的非空保证并非类型层面的「声明」而是由重载与条件类型双重约束下、被测试锁定的稳定契约。实践指南何时依赖 Defined 结果DefinedCreateQueryResult的价值在服务端渲染、乐观 UI 与「列表永不空白」类场景中尤为明显。以 packages/svelte-query/src/createQuery.ts:98-120 中的官方示例为例script langts import { createQuery } from tanstack/svelte-query // data 是 Post[]绝不会是 undefined——即使 refetch 失败 // 列表依然可见错误信息与之并存。 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} /ul使用要点initialData必须与TQueryFnData类型兼容DefinedInitialDataOptions要求其为NonUndefinedGuardTQueryFnData类型不符会在编译期报错createQueries测试中亦有ts-expect-error (initialData: string)的断言佐证见 packages/svelte-query/tests/createQueries/createQueries.test-d.ts:128-129区分initialData与placeholderDatainitialData会被写入缓存并视为真实数据影响gcTime/持久化而placeholderData仅用于展示层占位、不进入缓存见 packages/query-core/src/types.ts:428 的注释DefinedCreateQueryResult只由initialData触发可配合initialDataUpdatedAtQueryOptions支持initialDataUpdatedAt?: number | (() number | undefined)packages/query-core/src/types.ts:260用于让初始数据的「新鲜度时间戳」与后台 refetch 的staleTime判定协同工作避免初始数据被误判为过期而立即重取错误状态下的行为即使 refetch 失败由于DefinedQueryObserverResult只含success与refetchError两种分支data依旧保留初始值query.error与query.data可以同时存在——这正是上面示例中「错误提示 数据列表并存」的底气。小结DefinedCreateQueryResult是 TanStack Query Svelte 类型体系中的一个枢纽它以initialData为触发器通过重载createQuery/queryOptions与条件类型createQueries将「运行时已有数据」这一事实编码进类型系统最终让data在编译期保持非空。其底层依托tanstack/query-core的DefinedQueryObserverResult联合类型排除了pending/loading等无数据状态。无论是单查询还是并行查询只要提供非undefined的initialData你就能获得从数据声明到模板渲染全链路的类型安全。【免费下载链接】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),仅供参考