Skip to content

Conversation

@visz11
Copy link
Collaborator

@visz11 visz11 commented Oct 14, 2025

CodeAnt-AI Description

Fix setQueryData type inference so updater callback keeps correct types

What Changed

  • setQueryData's typing was adjusted so the updater callback retains the correct inferred data type even when used inside functions with explicit return types or when assigned to callbacks.
  • The Vue client binding was updated to match the core client so both surfaces preserve updater parameter types.
  • New tests cover updater usage in functions with explicit return types, expression-body arrow functions, and block-body arrow functions to prevent regressions.

Impact

✅ Fewer TypeScript errors when updater is used inside functions
✅ Better editor completions for setQueryData updater callbacks
✅ Consistent updater types in both core and Vue clients

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • Bug Fixes
    • Improved TypeScript typings for updating cached query data to preserve generic inference and prevent unintended type widening. Updater functions now receive correctly inferred types across usage patterns, including in the Vue adapter. No runtime behavior changes.
  • Tests
    • Added comprehensive type-level tests to validate updater parameter inference in different function forms and ensure improper usages are flagged by the type system.

@codeant-ai
Copy link

codeant-ai bot commented Oct 14, 2025

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@gemini-code-assist
Copy link

Summary of Changes

Hello @visz11, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a type inference issue within the setQueryData method across the query-core and vue-query packages. By leveraging the NoInfer utility type, it ensures that the return type of setQueryData is more accurately inferred, preventing type widening in certain scenarios. Additionally, new type definition tests have been introduced to validate that the updater function's parameter maintains correct type inference, particularly when setQueryData is embedded within functions with explicit return types like unknown or different arrow function syntaxes.

Highlights

  • Improved Type Inference for setQueryData: The return type of the setQueryData method in both query-core and vue-query packages has been updated to use the NoInfer utility type. This change ensures more precise type inference, preventing type widening in certain scenarios and maintaining stricter type safety.
  • Enhanced Type Definition Tests: New TypeScript definition tests have been added to validate that the data parameter within the setQueryData updater function correctly infers its type. These tests cover cases where setQueryData is used inside functions with explicit unknown return types and different arrow function body styles (expression and block), confirming the fix's effectiveness.
  • Cross-Package Consistency: The type inference fix and corresponding tests have been applied consistently across both the packages/query-core and packages/vue-query modules, ensuring uniform behavior and type safety for setQueryData in both environments.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Oct 14, 2025

Walkthrough

Updates typings for QueryClient.setQueryData in core and Vue packages to use NoInfer in return types. Adds new type-level tests validating updater parameter inference within functions with explicit return types and different arrow bodies. No runtime behavior changes are introduced.

Changes

Cohort / File(s) Summary of changes
Type tests: updater inference
packages/query-core/src/__tests__/queryClient.test-d.tsx, packages/vue-query/src/__tests__/queryClient.test-d.ts
Add type-focused tests ensuring updater receives number | undefined for tagged keys and remains correctly inferred inside functions with explicit return types; include ts-expect-error checks.
Core QueryClient typing
packages/query-core/src/queryClient.ts
Change setQueryData return type from TInferredQueryFnData | undefined to NoInfer | undefined.
Vue QueryClient typing
packages/vue-query/src/queryClient.ts
Update setQueryData overloads and implementation return types to NoInfer<...> | undefined; implementation delegates to super.setQueryData with cloneDeepUnref(options).

Sequence Diagram(s)

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

I twitch my ears at types that purr,
NoInfer hops in—no more blur.
Updaters nibble num or none,
In arrow fields, the checks are done.
Carrot-stamped tests all snug and bright,
I thump: the typings now feel right. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title mirrors the branch name and uses unclear phrasing like “Clone fix/preserve,” which does not succinctly describe the primary change to preserve setQueryData type inference through NoInfer. It fails to present a concise, single-sentence summary of the main modification introduced in the pull request. Please update the title to clearly and concisely reflect the main change, for example: “Preserve setQueryData type inference using NoInfer.”
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch clone-fix/preserve-set-query-data-type-inference

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5990e and 7c34847.

📒 Files selected for processing (4)
  • packages/query-core/src/__tests__/queryClient.test-d.tsx (2 hunks)
  • packages/query-core/src/queryClient.ts (1 hunks)
  • packages/vue-query/src/__tests__/queryClient.test-d.ts (1 hunks)
  • packages/vue-query/src/queryClient.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
packages/query-core/src/__tests__/queryClient.test-d.tsx (1)
packages/query-core/src/types.ts (1)
  • DataTag (66-75)
packages/vue-query/src/__tests__/queryClient.test-d.ts (1)
packages/query-core/src/types.ts (1)
  • DataTag (66-75)
packages/vue-query/src/queryClient.ts (3)
packages/query-core/src/types.ts (3)
  • NoInfer (30-30)
  • QueryKey (46-54)
  • SetDataOptions (1327-1329)
packages/vue-query/src/types.ts (2)
  • NoUnknown (39-39)
  • MaybeRefDeep (29-37)
packages/query-core/src/utils.ts (1)
  • Updater (70-70)
packages/query-core/src/queryClient.ts (1)
packages/query-core/src/types.ts (1)
  • NoInfer (30-30)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Preview
🔇 Additional comments (5)
packages/query-core/src/queryClient.ts (1)

188-188: LGTM! Type signature correctly preserves inference.

The addition of NoInfer to the return type prevents TypeScript from using return type context to influence the updater parameter's type inference, which is the intended fix for this PR.

packages/query-core/src/__tests__/queryClient.test-d.tsx (2)

117-128: LGTM! Test validates the type inference fix.

This test correctly verifies that the updater parameter maintains its inferred type (number | undefined) even when used inside a function with an explicit return type annotation (unknown). The use of satisfies is appropriate for this validation.


606-630: Clarify the expected errors in these tests.

The @ts-expect-error annotations suggest these assignments should fail type checking, but it's not immediately clear why assigning a function that returns number | undefined (or void) to a type expecting () => unknown would be an error, since unknown is the top type that accepts all values.

Could you clarify what specific type errors these tests are validating? Understanding the expected behavior would help verify the test assertions are correct.

packages/vue-query/src/__tests__/queryClient.test-d.ts (1)

100-111: LGTM! Test correctly validates type inference.

This test appropriately mirrors the core package test and verifies that updater parameter type inference is preserved in the Vue Query implementation when used within functions with explicit return types.

packages/vue-query/src/queryClient.ts (1)

117-117: LGTM! Type signatures correctly updated.

The addition of NoInfer to all three setQueryData signatures (both overloads and the implementation) correctly mirrors the core package changes and ensures consistent type inference behavior across the Vue Query implementation.

Also applies to: 122-122, 127-127


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai codeant-ai bot added the size:M This PR changes 30-99 lines, ignoring generated files label Oct 14, 2025
@visz11
Copy link
Collaborator Author

visz11 commented Oct 14, 2025

/refacto-visz

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a fix to preserve type inference for setQueryData's updater function, which is a great improvement for type safety. The changes in queryClient.ts for both query-core and vue-query correctly use NoInfer to prevent the contextual return type from incorrectly influencing type deduction.

The added tests effectively cover the scenarios this fix addresses. However, I've noticed a couple of @ts-expect-error directives in the new tests for query-core that seem to be incorrect now that the fix is in place. My review includes suggestions to remove them. Overall, this is a solid fix.

const queryKey = ['key'] as DataTag<Array<string>, number>
const queryClient = new QueryClient()

// @ts-expect-error

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

With the NoInfer fix on setQueryData, this assignment should be type-correct, and the type of data within the updater is correctly inferred. This means there should be no type error on the following line.

The @ts-expect-error directive is likely now causing an "Unused @ts-expect-error" warning from the TypeScript compiler and should be removed.

const queryKey = ['key'] as DataTag<Array<string>, number>
const queryClient = new QueryClient()

// @ts-expect-error

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the test above, this @ts-expect-error directive should be removed. The fix makes the assignment valid, so a type error is not expected.

>,
options?: MaybeRefDeep<SetDataOptions>,
): TInferredQueryFnData | undefined
): NoInfer<TInferredQueryFnData> | undefined
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Add a trailing semicolon to the overload signature to make it a proper TypeScript overload declaration. [possible bug]

Suggested change
): NoInfer<TInferredQueryFnData> | undefined
): NoInfer<TInferredQueryFnData> | undefined;
Why Change? ⭐

In TypeScript, overload signatures (declarations without an implementation) must be terminated with a semicolon.
The snippet being changed is an overload signature that precedes the implementation signature (which has a body).
Adding a trailing semicolon corrects the syntax without changing any runtime behavior. It does not reference any
identifiers outside the shown context and is consistent with the surrounding overload patterns in the file.
Assumptions: the next signature in the file is the implementation (has a function body), and the TypeScript
compiler expects overload terminators. This is a purely syntactic fix and will not introduce bugs.

updater: Updater<NoInfer<TData> | undefined, NoInfer<TData> | undefined>,
options?: MaybeRefDeep<SetDataOptions>,
): TData | undefined
): NoInfer<TData> | undefined
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Add a trailing semicolon to the second overload signature so both overloads are declared consistently and validly. [possible bug]

Suggested change
): NoInfer<TData> | undefined
): NoInfer<TData> | undefined;
Why Change? ⭐

This is the second overload signature in the same overload group. As with the first suggestion,
TypeScript overload signatures must end with semicolons. Adding the semicolon here fixes syntax,
keeps overload declarations consistent, and does not alter runtime semantics. The change purely
affects declaration syntax and relies only on surrounding code already present in the file (the
implementation signature with a body follows). No new identifiers or behavior are introduced.

@refacto-visz
Copy link

refacto-visz bot commented Oct 14, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

@codeant-ai
Copy link

codeant-ai bot commented Oct 14, 2025

Pull Request Feedback 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Generic parameter erosion
    defaultQueryOptions is called with the concrete generic QueryKey which may erase tag information from TTaggedQueryKey. Confirm the change to use NoInfer in the return doesn't hide a root cause where the call-site generics should preserve TTaggedQueryKey.

  • Overload / Implementation Mismatch
    The first setQueryData overload accepts a plain TTaggedQueryKey but the implementation accepts MaybeRefDeep<QueryKey> (and calls cloneDeepUnref). This can cause mismatch in how callers using refs are typed vs how the implementation treats them, potentially affecting inference in some call sites. Verify callers that rely on tag-based inference still get correct types when passing refs.

  • Inconsistent Inference for setQueriesData
    The PR updates setQueryData overloads to return NoInfer<...> | undefined to preserve inference for updater callbacks, but setQueriesData still returns Array<[QueryKey, TData | undefined]> (uses plain TData). Consider whether setQueriesData should also use NoInfer<TData> in its return signature to provide consistent inference for updater callbacks used there.

  • Cross-surface consistency
    The PR description mentions matching the Vue client surface. Ensure equivalent typing changes (if required) are applied in other client implementations (Vue, react bindings, wrappers) and that tests exercising arrow functions, explicit returns, and callback assignments pass across all surfaces.

  • ASI / formatting fragility
    The leading semicolon before the parenthesized arrow expression (to avoid ASI) can be fragile to automatic formatting or refactors. Ensure formatters and linters won't remove or reformat it in a way that changes semantics.

  • Test duplication / maintainability
    The same assertion pattern for updater parameter inference is repeated across three added tests (explicit-return function, expression arrow, block arrow). Consider centralizing to avoid duplication and reduce maintenance burden.

>,
options?: SetDataOptions,
): TInferredQueryFnData | undefined {
): NoInfer<TInferredQueryFnData> | undefined {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Revert the explicit NoInfer return type on setQueryData back to the original inferred return type to avoid surprising inference changes for direct-value callers; alternatively, if keeping NoInfer here, apply NoInfer consistently to the related setQueriesData return type — ensure updater inference and consumers' expectations remain stable. [possible issue]

@refacto-visz
Copy link

refacto-visz bot commented Oct 14, 2025

Code Review: TypeScript Type Safety Enhancement

👍 Well Done
Type Safety Enhancement

NoInfer wrapper prevents type widening preserving generic inference reliability across core and Vue implementations

Comprehensive Test Coverage

Tests validate type inference across multiple function patterns preventing regressions with specific edge case scenarios

📁 Selected files for review (4)
  • packages/query-core/src/__tests__/queryClient.test-d.tsx
  • packages/query-core/src/queryClient.ts
  • packages/vue-query/src/__tests__/queryClient.test-d.ts
  • packages/vue-query/src/queryClient.ts
🎯 Custom Instructions
✅ Applied Instructions
Organization Guidelines
  • Avoid commented code in actual codebases
  • Hardcoding of variables

Scope: All files

📝 Additional Comments
packages/query-core/src/queryClient.ts (3)
Type Inference Protection

NoInfer utility type prevents TypeScript from widening generic types during inference, maintaining type safety by preserving exact parameter types in updater callbacks and preventing runtime type mismatches.

Standards:

  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • ISO-IEC-25010-Reliability-Maturity
Type Inference Optimization

NoInfer wrapper prevents TypeScript from performing type inference on return type, potentially reducing compiler optimization opportunities. While improving type safety, this may slightly increase compilation time for complex generic scenarios.

Standards:

  • ISO-IEC-25010-Performance-Efficiency-Time-Behavior
  • TypeScript-Compilation-Optimization
Type System Hardening

Enhanced type inference with NoInfer prevents unintended type widening that could mask type-related security issues, reducing risk of type confusion vulnerabilities where incorrect data types bypass validation logic.

Standards:

  • CWE-843
  • OWASP-A04
  • NIST-SSDF-PW.1
packages/query-core/src/__tests__/queryClient.test-d.tsx (1)
Test Coverage Enhancement

Test expects TypeScript error but doesn't validate the specific error type or message. Enhanced error validation would ensure the type system correctly identifies the inference preservation issue and strengthen type safety verification.

Standards:

  • Algorithm-Correctness-Type-System
  • Logic-Verification-Test-Coverage

>,
options?: SetDataOptions,
): TInferredQueryFnData | undefined {
): NoInfer<TInferredQueryFnData> | undefined {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type Safety Pattern Enhancement

NoInfer wrapper prevents TypeScript from widening generic types in complex inference scenarios, maintaining type safety when setQueryData is used in functions with explicit return types. This ensures consistent type behavior across different usage patterns and prevents runtime type mismatches.

Standards
  • Clean-Code-Type-Safety
  • SOLID-OCP
  • Maintainability-Quality-Consistency

@codeant-ai
Copy link

codeant-ai bot commented Oct 14, 2025

CodeAnt AI finished reviewing your PR.

Comment on lines +117 to +127
): NoInfer<TInferredQueryFnData> | undefined
setQueryData<TQueryFnData, TData = NoUnknown<TQueryFnData>>(
queryKey: MaybeRefDeep<QueryKey>,
updater: Updater<NoInfer<TData> | undefined, NoInfer<TData> | undefined>,
options?: MaybeRefDeep<SetDataOptions>,
): TData | undefined
): NoInfer<TData> | undefined
setQueryData<TData>(
queryKey: MaybeRefDeep<QueryKey>,
updater: Updater<TData | undefined, TData | undefined>,
options: MaybeRefDeep<SetDataOptions> = {},
): TData | undefined {
): NoInfer<TData> | undefined {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vue Consistency Pattern

Vue client maintains type inference consistency with core client through NoInfer wrapper application. This prevents type widening in Vue-specific contexts while preserving generic type relationships, ensuring consistent developer experience across both implementations.

Standards
  • Clean-Code-Consistency
  • SOLID-LSP
  • Maintainability-Quality-Interface-Consistency

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants