Svelte Query 的 CreateMutationOptions:createMutation 完整配置类型解析与源码级实现
【免费下载链接】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
导读
CreateMutationOptions是 @tanstack/svelte-query 中createMutation的选项类型别名,它规定了 Svelte 应用中一切变更操作(创建、更新、删除数据或执行服务端副作用)的配置契约。本文从该类型的定义出发,逐一解析其四个泛型参数、继承自核心包的十余个配置字段,并结合 createMutation.svelte.ts 的实现与类型测试,说明这些选项在响应式环境中的真实运行机制。读完本文,你将能写出类型完备、推断精准、支持乐观更新与全局状态查询的 Svelte Query 变更逻辑。
CreateMutationOptions 的定义与定位
在 packages/svelte-query/src/types.ts 中,该类型定义如下:
/** Options for createMutation */ export type CreateMutationOptions< TData = unknown, TError = DefaultError, TVariables = void, TOnMutateResult = unknown, > = OmitKeyof< MutationObserverOptions<TData, TError, TVariables, TOnMutateResult>, '_defaulted' >官方类型参考页对其的说明只有一句话:Options for createMutation(createMutation的选项)。从源码结构看,它本质上是对核心包@tanstack/query-core中MutationObserverOptions的再封装,唯一的变化是借助OmitKeyof工具类型剔除内部的_defaulted标记字段——该字段是查询/变更观察器在内部完成选项默认值填充后设置的内部标志(源码位于 packages/query-core/src/types.ts),对外部调用方没有意义,因此从公共 API 中隐藏。
OmitKeyof与MutationObserverOptions均从@tanstack/query-core导入(见 types.ts),这体现了 svelte-query 作为框架适配层、query-core 承载全部通用逻辑的分层设计。
四个类型参数:含义与默认值
原类型参考页对每个泛型参数给出了默认值,逐项说明如下:
| 类型参数 | 默认值 | 含义 |
|---|---|---|
TData | unknown | mutationFn成功 resolve 后的数据类型,会作为onSuccess第一个参数与返回结果中data字段的类型 |
TError | DefaultError | 变更失败时的错误类型,默认是核心包定义的DefaultError(即Error),会作为onError第一个参数与结果中error字段的类型 |
TVariables | void | mutationFn接收的变量(入参)类型,决定mutate/mutateAsync的入参类型 |
TOnMutateResult | unknown | onMutate回调的返回值类型,用于乐观更新时携带上下文(context),失败时透传给onError作为第三个参数 |
TOnMutateResult:乐观更新的上下文通道
TOnMutateResult是四个参数中最具实战意义的一个。它的典型用法是:在onMutate中先取消进行中的查询、保存旧数据并提前写入新数据(乐观 UI),然后把旧数据作为返回值;若变更失败,onError通过第三个参数拿到该返回值并回滚。这一模式被封装进类型系统,createMutation.test-d.ts 中的类型测试验证了onMutate返回{ token: string }时,onSuccess收到类型为{ token: string },而onError收到{ token: string } | undefined——因为onError在onMutate失败或未定义时确实可能拿到undefined。
完整选项字段清单:继承自 MutationObserverOptions
由于CreateMutationOptions直接展开自MutationObserverOptions,后者的全部字段即前者可用的全部配置。MutationObserverOptions在 packages/query-core/src/types.ts 中定义,它先继承MutationOptions的全部字段,再额外增加throwOnError。逐字段说明:
MutationOptions 基础字段
mutationFn?: MutationFunction<TData, TVariables>:执行变更的核心函数,接收(variables, context),返回Promise<TData>。context为MutationFunctionContext,包含client、meta与可选的mutationKey。mutationKey?: MutationKey:变更的唯一标识(只读数组),用于配合useMutationState跨组件定位该变更。onMutate?: (variables, context) => Promise<TOnMutateResult> | TOnMutateResult:变更执行前同步触发,常用于乐观更新与副作用准备。onSuccess?: (data, variables, onMutateResult, context) => ...:变更成功后触发。onError?: (error, variables, onMutateResult | undefined, context) => ...:变更失败后触发,onMutateResult在onMutate未返回或自身抛错时为undefined。onSettled?: (data | undefined, error | null, variables, onMutateResult | undefined, context) => ...:无论成败都会触发,适合做收尾(如失效查询)。retry?: RetryValue<TError>:失败重试次数或重试判定函数(boolean | number | (failureCount, error) => boolean)。retryDelay?: RetryDelayValue<TError>:重试间隔,可为数值或基于failureCount与error计算延迟的函数。networkMode?: NetworkMode:网络模式,取值如'online'/'offlineFirst'/'always',控制离线时的执行策略。gcTime?: number:变更从内存中被垃圾回收前的保留时间(毫秒)。meta?: MutationMeta:附加到变更上的任意元数据,可在MutationFunctionContext中读取。scope?: MutationScope:变更作用域({ id: string }),用于控制变更的并发隔离。_defaulted?: boolean:内部字段,已被OmitKeyof从公共类型中剔除。
MutationObserverOptions 独有字段
throwOnError?: boolean | ((error: TError) => boolean):当为true或判定函数返回true时,mutateAsync返回的 Promise 会以错误拒绝而非吞掉错误;在 Svelte 中还可与错误边界(error boundary)配合使用。该字段是MutationObserverOptions相比MutationOptions唯一的新增项(见 types.ts)。
与 createMutation 的配合:选项的响应式形态
CreateMutationOptions并非孤立存在,它是createMutation的第一个参数类型。在 createMutation.svelte.ts 中:
export function createMutation< TData = unknown, TError = DefaultError, TVariables = void, TContext = unknown, >( options: Accessor<CreateMutationOptions<TData, TError, TVariables, TContext>>, queryClient?: Accessor<QueryClient>, ): CreateMutationResult<TData, TError, TVariables, TContext>两个关键点:
- 选项是响应式读取器:
options的类型是Accessor<T> = () => T(见 types.ts),即一个返回CreateMutationOptions的函数。这意味着你传入的配置对象本身可以是 Svelte 5 runes 的派生值,选项变化时会自动生效。 - 可指定自定义 QueryClient:第二个参数同样是
Accessor<QueryClient>,缺省时使用最近上下文中的QueryClient。
运行时实现要点
从 createMutation.svelte.ts 的实现可以推断其底层机制:
- 内部持有
MutationObserver(来自@tanstack/query-core),其构造与重建由watchChanges监听client变化触发; $effect.pre中调用observer.setOptions(options()),使选项的响应式更新同步到观察器;- 返回结果通过
Proxy包装:mutate与mutateAsync被注入结果对象,mutateAsync实际复用观察器自身的mutate(返回 Promise),而mutate则调用后catch(noop)吞掉未处理的拒绝; - 状态字段(
isPending、status、data、error等)由观察器的订阅回调批量写入,通知经由notifyManager.batchCalls合并。
最小可用示例
<script lang="ts"> import { createMutation, useQueryClient } from '@tanstack/svelte-query' const queryClient = useQueryClient() const addMutation = createMutation(() => ({ mutationFn: addTodo, // (variables: string) => Promise<Todo> onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }), })) </script> {#if addMutation.isPending} 正在添加… {:else if addMutation.isError} 添加失败:{addMutation.error.message} {:else} <button onclick={() => addMutation.mutate('Item')}>Add</button> {/if}此示例中无需显式标注任何泛型——TData、TVariables均从mutationFn自动推断。类型测试证实了以下推断行为(见 createMutation.test-d.ts):
mutationFn: () => Promise.resolve('data')时,data推断为string | undefined,error为DefaultError | null;mutationFn: (vars: { id: string }) => ...时,mutate仅接受{ id: string };- 无参
mutationFn时TVariables默认void,mutate()可不带参数调用; - 自定义错误类可通过
createMutation<string, CustomError>(...)显式传入,error随之推断为CustomError | null; mutateAsync的返回类型与mutationFn的 Promise 泛型一致,如Promise<number>。
对应的运行时测试位于 createMutation.svelte.test.ts,覆盖了reset清除错误、多次mutate的onSuccess/onSettled触发次数、failureCount/failureReason在多轮调用间的正确归零与更新,以及QueryClient切换时观察器重建等行为。
共享选项:mutationOptions 与类型的关系
当需要在多个createMutation调用点之间共享同一份CreateMutationOptions,或希望借助mutationKey在组件外查询变更状态时,官方推荐mutationOptions辅助函数。它提供两个重载(见 mutationOptions.md):
- 要求
mutationKey的重载:返回WithRequired<CreateMutationOptions<...>, 'mutationKey'>,适合配合useMutationState实现全局"保存中…"指示器; - 不要求
mutationKey的重载:返回Omit<CreateMutationOptions<...>, 'mutationKey'>,适合单纯共享配置。
<script lang="ts"> import { mutationOptions, createMutation } from '@tanstack/svelte-query' const createPostOptions = mutationOptions({ mutationKey: ['posts', 'create'], mutationFn: createPost, }) const mutation = createMutation(() => createPostOptions) </script> <button onclick={() => mutation.mutate({ title: 'Hello' })}>Create</button>mutationOptions的返回值本身就是CreateMutationOptions的派生形态,可直接塞进createMutation的Accessor中,二者类型天然兼容。
相关类型链
围绕CreateMutationOptions,types.ts 中还定义了一组配套类型,理解它们有助于掌握完整类型系统:
CreateMutationResult<TData, TError, TVariables, TOnMutateResult>:createMutation的返回值,在核心包MutationObserverResult基础上重写了mutate(CreateMutateFunction,返回void)并追加mutateAsync(CreateMutateAsyncFunction,返回 Promise)。CreateMutateFunction/CreateMutateAsyncFunction:分别对应同步触发与可等待的触发函数形态。MutationStateOptions与MutationTypeFromResult:服务于useMutationState的过滤器与类型提取。
结语
CreateMutationOptions虽只是一行类型别名,却是 svelte-query 变更体系(createMutation→MutationObserver→Mutation)的配置入口。理解它的四个泛型参数与全部字段,意味着你同时理解了 query-core 中MutationObserverOptions的能力边界;再结合Accessor包裹的响应式形态,即可在 Svelte 5 的 runes 体系下写出类型安全、状态可控、可全局追踪的完整变更方案。若要深入底层执行与重试细节,可继续阅读 packages/query-core/src/mutationObserver.ts 与 packages/query-core/src/mutationCache.ts 中的观察器与缓存实现。
【免费下载链接】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),仅供参考