Svelte Query 的 CreateMutationOptions:createMutation 完整配置类型解析与源码级实现
2026/9/10 1:34:55 网站建设 项目流程

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 createMutationcreateMutation的选项)。从源码结构看,它本质上是对核心包@tanstack/query-coreMutationObserverOptions的再封装,唯一的变化是借助OmitKeyof工具类型剔除内部的_defaulted标记字段——该字段是查询/变更观察器在内部完成选项默认值填充后设置的内部标志(源码位于 packages/query-core/src/types.ts),对外部调用方没有意义,因此从公共 API 中隐藏。

OmitKeyofMutationObserverOptions均从@tanstack/query-core导入(见 types.ts),这体现了 svelte-query 作为框架适配层、query-core 承载全部通用逻辑的分层设计。

四个类型参数:含义与默认值

原类型参考页对每个泛型参数给出了默认值,逐项说明如下:

类型参数默认值含义
TDataunknownmutationFn成功 resolve 后的数据类型,会作为onSuccess第一个参数与返回结果中data字段的类型
TErrorDefaultError变更失败时的错误类型,默认是核心包定义的DefaultError(即Error),会作为onError第一个参数与结果中error字段的类型
TVariablesvoidmutationFn接收的变量(入参)类型,决定mutate/mutateAsync的入参类型
TOnMutateResultunknownonMutate回调的返回值类型,用于乐观更新时携带上下文(context),失败时透传给onError作为第三个参数

TOnMutateResult:乐观更新的上下文通道

TOnMutateResult是四个参数中最具实战意义的一个。它的典型用法是:在onMutate中先取消进行中的查询、保存旧数据并提前写入新数据(乐观 UI),然后把旧数据作为返回值;若变更失败,onError通过第三个参数拿到该返回值并回滚。这一模式被封装进类型系统,createMutation.test-d.ts 中的类型测试验证了onMutate返回{ token: string }时,onSuccess收到类型为{ token: string },而onError收到{ token: string } | undefined——因为onErroronMutate失败或未定义时确实可能拿到undefined

完整选项字段清单:继承自 MutationObserverOptions

由于CreateMutationOptions直接展开自MutationObserverOptions,后者的全部字段即前者可用的全部配置。MutationObserverOptions在 packages/query-core/src/types.ts 中定义,它先继承MutationOptions的全部字段,再额外增加throwOnError。逐字段说明:

MutationOptions 基础字段

  • mutationFn?: MutationFunction<TData, TVariables>:执行变更的核心函数,接收(variables, context),返回Promise<TData>contextMutationFunctionContext,包含clientmeta与可选的mutationKey
  • mutationKey?: MutationKey:变更的唯一标识(只读数组),用于配合useMutationState跨组件定位该变更。
  • onMutate?: (variables, context) => Promise<TOnMutateResult> | TOnMutateResult:变更执行前同步触发,常用于乐观更新与副作用准备。
  • onSuccess?: (data, variables, onMutateResult, context) => ...:变更成功后触发。
  • onError?: (error, variables, onMutateResult | undefined, context) => ...:变更失败后触发,onMutateResultonMutate未返回或自身抛错时为undefined
  • onSettled?: (data | undefined, error | null, variables, onMutateResult | undefined, context) => ...:无论成败都会触发,适合做收尾(如失效查询)。
  • retry?: RetryValue<TError>:失败重试次数或重试判定函数(boolean | number | (failureCount, error) => boolean)。
  • retryDelay?: RetryDelayValue<TError>:重试间隔,可为数值或基于failureCounterror计算延迟的函数。
  • 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>

两个关键点:

  1. 选项是响应式读取器options的类型是Accessor<T> = () => T(见 types.ts),即一个返回CreateMutationOptions的函数。这意味着你传入的配置对象本身可以是 Svelte 5 runes 的派生值,选项变化时会自动生效。
  2. 可指定自定义 QueryClient:第二个参数同样是Accessor<QueryClient>,缺省时使用最近上下文中的QueryClient

运行时实现要点

从 createMutation.svelte.ts 的实现可以推断其底层机制:

  • 内部持有MutationObserver(来自@tanstack/query-core),其构造与重建由watchChanges监听client变化触发;
  • $effect.pre中调用observer.setOptions(options()),使选项的响应式更新同步到观察器;
  • 返回结果通过Proxy包装:mutatemutateAsync被注入结果对象,mutateAsync实际复用观察器自身的mutate(返回 Promise),而mutate则调用后catch(noop)吞掉未处理的拒绝;
  • 状态字段(isPendingstatusdataerror等)由观察器的订阅回调批量写入,通知经由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}

此示例中无需显式标注任何泛型——TDataTVariables均从mutationFn自动推断。类型测试证实了以下推断行为(见 createMutation.test-d.ts):

  • mutationFn: () => Promise.resolve('data')时,data推断为string | undefinederrorDefaultError | null
  • mutationFn: (vars: { id: string }) => ...时,mutate仅接受{ id: string }
  • 无参mutationFnTVariables默认voidmutate()可不带参数调用;
  • 自定义错误类可通过createMutation<string, CustomError>(...)显式传入,error随之推断为CustomError | null
  • mutateAsync的返回类型与mutationFn的 Promise 泛型一致,如Promise<number>

对应的运行时测试位于 createMutation.svelte.test.ts,覆盖了reset清除错误、多次mutateonSuccess/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的派生形态,可直接塞进createMutationAccessor中,二者类型天然兼容。

相关类型链

围绕CreateMutationOptions,types.ts 中还定义了一组配套类型,理解它们有助于掌握完整类型系统:

  • CreateMutationResult<TData, TError, TVariables, TOnMutateResult>createMutation的返回值,在核心包MutationObserverResult基础上重写了mutateCreateMutateFunction,返回void)并追加mutateAsyncCreateMutateAsyncFunction,返回 Promise)。
  • CreateMutateFunction/CreateMutateAsyncFunction:分别对应同步触发与可等待的触发函数形态。
  • MutationStateOptionsMutationTypeFromResult:服务于useMutationState的过滤器与类型提取。

结语

CreateMutationOptions虽只是一行类型别名,却是 svelte-query 变更体系(createMutationMutationObserverMutation)的配置入口。理解它的四个泛型参数与全部字段,意味着你同时理解了 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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询