Summary
The TMutation generic added to useMutationState (and its equivalents across all adapters) includes a safety warning, but the warning only appears on the MutationStateOptions type definition — not on the hook function itself. In practice, users hover over the function, not the type, so the warning is effectively invisible in most IDEs.
Affected version
Introduced in the TMutation generic PR targeting v5.x (current: v5.100.14). Not present in v4 (no useMutationState).
Affected packages
All adapters updated in the TMutation PR:
@tanstack/react-query
@tanstack/vue-query
@tanstack/solid-query
@tanstack/svelte-query
@tanstack/preact-query
@tanstack/lit-query
Current behavior
The warning lives only on the type parameter of MutationStateOptions:
// ✅ Warning is here — but users rarely hover over a type definition
type MutationStateOptions<
TResult = MutationState,
/**
* Narrows the type of the `mutation` argument passed to `select`.
* This is a caller-side assertion — the mutation cache stores mutations as
* the base `Mutation` type, so it is the caller's responsibility to ensure
* `TMutation` matches the actual mutations in the cache (e.g. by specifying
* a `mutationKey` in `filters`).
*/
TMutation extends Mutation<any, any, any, any> = Mutation,
> = { ... }
// ❌ No warning here — but this is where users look
export function useMutationState<
TResult = MutationState,
TMutation extends Mutation<any, any, any, any> = Mutation,
>(options: MutationStateOptions<TResult, TMutation> = {}, ...): Array<TResult>
Why this matters
The as unknown as TMutation cast inside getResult() completely bypasses TypeScript's structural type checker at runtime. There is no runtime guard that validates the actual cache entry matches TMutation. If a user specifies TMutation without using filters to narrow the cache to matching mutations, TypeScript will silently accept incorrect code:
// TypeScript: ✅ Runtime: 💥 (cache may hold Mutation<OrderData>, not Mutation<UserData>)
const states = useMutationState<MutationState<UserData>, Mutation<UserData>>({
// ⚠️ No mutationKey filter — any mutation in the cache will be cast to Mutation<UserData>
select: (m) => m.state.data, // typed as UserData | undefined, but could be anything
})
The feature is a deliberate caller-side assertion (similar to as casts), which is a reasonable design. The problem is that the responsibility is not communicated at the call site.
Expected behavior
The useMutationState function (and equivalents in all adapters) should have a JSDoc comment on the TMutation type parameter explaining:
- This is a caller-side assertion, not a runtime-verified narrowing.
- TypeScript will not catch type mismatches between
TMutation and the actual cache contents.
- Users should always pair
TMutation with a filters.mutationKey (or equivalent) to ensure only matching mutations are selected.
Suggested fix
Add a JSDoc comment on the TMutation parameter of the exported hook function, mirroring the one already on MutationStateOptions:
export function useMutationState<
TResult = MutationState,
/**
* Narrows the type of the `mutation` argument passed to `select`.
* **This is a caller-side assertion with no runtime validation.**
* The mutation cache stores all mutations as the base `Mutation` type,
* so TypeScript will not catch a mismatch between `TMutation` and the
* actual mutations in the cache.
* Always use `filters` (e.g. `mutationKey`) to ensure only mutations of
* the expected type are matched.
*/
TMutation extends Mutation<any, any, any, any> = Mutation,
>(options: MutationStateOptions<TResult, TMutation> = {}, ...): Array<TResult>
The same change should be applied to the equivalent function in all six adapters.
Additional context
- This was identified during review of the
TMutation generic PR.
- The same
as unknown as TMutation cast exists identically in react-query, vue-query, solid-query, svelte-query, preact-query, and lit-query — so the fix is mechanical and low-risk once the right wording is agreed on.
Summary
The
TMutationgeneric added touseMutationState(and its equivalents across all adapters) includes a safety warning, but the warning only appears on theMutationStateOptionstype definition — not on the hook function itself. In practice, users hover over the function, not the type, so the warning is effectively invisible in most IDEs.Affected version
Introduced in the
TMutationgeneric PR targetingv5.x(current:v5.100.14). Not present in v4 (nouseMutationState).Affected packages
All adapters updated in the
TMutationPR:@tanstack/react-query@tanstack/vue-query@tanstack/solid-query@tanstack/svelte-query@tanstack/preact-query@tanstack/lit-queryCurrent behavior
The warning lives only on the type parameter of
MutationStateOptions:Why this matters
The
as unknown as TMutationcast insidegetResult()completely bypasses TypeScript's structural type checker at runtime. There is no runtime guard that validates the actual cache entry matchesTMutation. If a user specifiesTMutationwithout usingfiltersto narrow the cache to matching mutations, TypeScript will silently accept incorrect code:The feature is a deliberate caller-side assertion (similar to
ascasts), which is a reasonable design. The problem is that the responsibility is not communicated at the call site.Expected behavior
The
useMutationStatefunction (and equivalents in all adapters) should have a JSDoc comment on theTMutationtype parameter explaining:TMutationand the actual cache contents.TMutationwith afilters.mutationKey(or equivalent) to ensure only matching mutations are selected.Suggested fix
Add a JSDoc comment on the
TMutationparameter of the exported hook function, mirroring the one already onMutationStateOptions:The same change should be applied to the equivalent function in all six adapters.
Additional context
TMutationgeneric PR.as unknown as TMutationcast exists identically in react-query, vue-query, solid-query, svelte-query, preact-query, and lit-query — so the fix is mechanical and low-risk once the right wording is agreed on.