Skip to content

fix(query-core): stop wrapping persister generics in NoInfer#10510

Merged
TkDodo merged 4 commits intoTanStack:mainfrom
ousamabenyounes:fix/issue-7842
Apr 25, 2026
Merged

fix(query-core): stop wrapping persister generics in NoInfer#10510
TkDodo merged 4 commits intoTanStack:mainfrom
ousamabenyounes:fix/issue-7842

Conversation

@ousamabenyounes
Copy link
Copy Markdown
Contributor

@ousamabenyounes ousamabenyounes commented Apr 16, 2026

Summary

Fixes #7842.

QueryOptions.persister was typed as QueryPersister<NoInfer<TQueryFnData>, NoInfer<TQueryKey>, NoInfer<TPageParam>>, which prevented the persister from contributing to TQueryFnData inference. When the companion queryFn declared a parameter (e.g. (_context) => 'test'), TypeScript failed to infer TQueryFnData from its return and defaulted to unknown, producing a spurious overload mismatch against a concretely-typed persister.

Removing the NoInfer wrappers lets persister participate in inference. queryFn still drives inference when the types agree, and genuine conflicts between persister and queryFn still surface as errors (covered by a new negative type test in queryOptions.test-d.tsx).

Repro

declare function createPersister<TData>(): QueryPersister<TData, any>

// Works (baseline)
queryOptions({
  queryKey: ['a'],
  queryFn: () => 'hello',
  persister: createPersister<string>(),
})

// BEFORE: TS2769 "No overload matches this call"
// AFTER: compiles cleanly
queryOptions({
  queryKey: ['b'],
  queryFn: (_context) => 'hello',
  persister: createPersister<string>(),
})

Verification

  • packages/query-core type tests: pass across TS 5.4, 5.8, 6.0 current (tsc --build tsconfig.legacy.json)
  • packages/react-query type tests: pass (new positive + negative cases in queryOptions.test-d.tsx)
  • packages/vue-query, packages/solid-query, packages/preact-query type tests: pass
  • Genuine type conflicts (e.g. queryFn: () => 42 with persister: QueryPersister<string>) still produce the expected overload mismatch — verified by the new @ts-expect-error cases.

Changeset

@tanstack/query-core: patch — type-only change, no runtime behaviour affected.

🤖 Generated with Ora Studio

Summary by CodeRabbit

  • Bug Fixes

    • Improved TypeScript inference for typed persisters so query functions that accept parameters no longer produce spurious overload mismatch errors, enhancing type safety and IDE experience for parameterized queries.
  • Tests

    • Added type-level tests to confirm correct inference from persisters and to ensure genuine type conflicts remain reported.

The `persister` field on QueryOptions was typed as
`QueryPersister<NoInfer<TQueryFnData>, NoInfer<TQueryKey>, NoInfer<TPageParam>>`
so persister could not contribute to TQueryFnData inference. When the
companion queryFn declared a parameter (e.g. `(_context) => 'test'`),
TypeScript failed to infer TQueryFnData from its return and defaulted
to `unknown`, causing a spurious overload mismatch against a
concretely-typed persister (fixes TanStack#7842).

Removing the NoInfer wrappers lets persister participate in inference.
Genuine type conflicts between persister and queryFn still surface as
errors (covered by a new negative type test in queryOptions.test-d.tsx).

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 07a8672c-626b-4234-b1f1-0e49a05efb8f

📥 Commits

Reviewing files that changed from the base of the PR and between cbc0246 and 9323f98.

📒 Files selected for processing (1)
  • packages/query-core/src/types.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/query-core/src/types.ts

📝 Walkthrough

Walkthrough

This PR removes NoInfer<> wrappers from the persister property in QueryOptions so a typed persister can participate in inferring TQueryFnData even when queryFn declares parameters. Type-tests were added to assert correct inference and to assert real mismatches still error.

Changes

Cohort / File(s) Summary
Changeset Documentation
\.changeset/fix-persister-infer-when-queryfn-has-parameter.md
Added a changeset declaring a patch release for @tanstack/query-core documenting the persister type-inference fix.
Type Definition
packages/query-core/src/types.ts
Removed NoInfer<> wrappers from QueryOptions.persister, changing its type to QueryPersister<TQueryFnData, TQueryKey, TPageParam> so persister can influence TQueryFnData inference.
Type Tests
packages/react-query/src/__tests__/queryOptions.test-d.tsx
Added type-test cases: one confirming inference from persister when queryFn has a context/argument, and negative // @ts-expect-error`` tests verifying genuine type mismatches still fail.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇
I hopped through types both near and far,
Removed the fences, freed the spar,
Persister whispers what data should be,
QueryFn with args now learns from me,
A tiny chew, a joyous star.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: removing NoInfer wrappers from persister generics in QueryOptions to fix type inference issues.
Description check ✅ Passed The description is comprehensive, including the issue fix, detailed explanation, reproduction case, verification results, and a changeset declaration matching the template.
Linked Issues check ✅ Passed All code changes directly address the requirements in issue #7842: removed NoInfer wrappers from QueryPersister generics to allow persister participation in TQueryFnData inference, with comprehensive type test coverage ensuring both positive cases and genuine type conflicts are properly handled.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing issue #7842: changeset documentation, QueryOptions type definition update, and type test additions with no unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/react-query/src/__tests__/queryOptions.test-d.tsx (1)

303-319: Minor: silence vitest/expect-expect for this type-only negative test.

ESLint flags this test as having no assertions because @ts-expect-error is the implicit assertion. Either disable the rule locally or wrap the calls in assertType(...) to satisfy the linter.

Proposed fix
-  it('should still error when persister and queryFn return types genuinely conflict', () => {
+  // eslint-disable-next-line vitest/expect-expect
+  it('should still error when persister and queryFn return types genuinely conflict', () => {
     const persister = undefined as unknown as QueryPersister<string, any>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-query/src/__tests__/queryOptions.test-d.tsx` around lines 303
- 319, This test is a type-only negative test using `@ts-expect-error` but
triggers the vitest/expect-expect lint rule; either disable the rule locally for
this block or add a no-op type assertion to make ESLint happy. Modify the test
in packages/react-query/src/__tests__/queryOptions.test-d.tsx around the two
queryOptions(...) calls: either add an inline ESLint disable comment for
"vitest/expect-expect" scoped to the test, or wrap each call with a type-level
helper such as assertType<unknown>(queryOptions(...)) (or another existing
assertType utility) so the linter sees an assertion while preserving the
`@ts-expect-error` checks on queryFn vs persister.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/react-query/src/__tests__/queryOptions.test-d.tsx`:
- Around line 303-319: This test is a type-only negative test using
`@ts-expect-error` but triggers the vitest/expect-expect lint rule; either disable
the rule locally for this block or add a no-op type assertion to make ESLint
happy. Modify the test in
packages/react-query/src/__tests__/queryOptions.test-d.tsx around the two
queryOptions(...) calls: either add an inline ESLint disable comment for
"vitest/expect-expect" scoped to the test, or wrap each call with a type-level
helper such as assertType<unknown>(queryOptions(...)) (or another existing
assertType utility) so the linter sees an assertion while preserving the
`@ts-expect-error` checks on queryFn vs persister.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 878349b8-d2be-4c9a-816a-c2d3de88ede1

📥 Commits

Reviewing files that changed from the base of the PR and between dbee9eb and 1546819.

📒 Files selected for processing (3)
  • .changeset/fix-persister-infer-when-queryfn-has-parameter.md
  • packages/query-core/src/types.ts
  • packages/react-query/src/__tests__/queryOptions.test-d.tsx

Addresses CodeRabbit nitpick: vitest/expect-expect flagged the
genuine-conflict test as having no assertions. Wrap both calls in
assertType() so the linter sees an explicit assertion while the
`@ts-expect-error` directives continue to enforce the type mismatch.

Co-Authored-By: Claude <noreply@anthropic.com>
@ousamabenyounes
Copy link
Copy Markdown
Contributor Author

Addressed the vitest/expect-expect nitpick in cbc0246 — both negative cases are now wrapped in assertType(...). Types + ESLint both pass locally. Thanks for the review!

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Apr 25, 2026

View your CI Pipeline Execution ↗ for commit 85317f2

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 6m 7s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-25 09:36:29 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 25, 2026

More templates

@tanstack/angular-query-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-experimental@10510

@tanstack/eslint-plugin-query

npm i https://pkg.pr.new/@tanstack/eslint-plugin-query@10510

@tanstack/preact-query

npm i https://pkg.pr.new/@tanstack/preact-query@10510

@tanstack/preact-query-devtools

npm i https://pkg.pr.new/@tanstack/preact-query-devtools@10510

@tanstack/preact-query-persist-client

npm i https://pkg.pr.new/@tanstack/preact-query-persist-client@10510

@tanstack/query-async-storage-persister

npm i https://pkg.pr.new/@tanstack/query-async-storage-persister@10510

@tanstack/query-broadcast-client-experimental

npm i https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@10510

@tanstack/query-core

npm i https://pkg.pr.new/@tanstack/query-core@10510

@tanstack/query-devtools

npm i https://pkg.pr.new/@tanstack/query-devtools@10510

@tanstack/query-persist-client-core

npm i https://pkg.pr.new/@tanstack/query-persist-client-core@10510

@tanstack/query-sync-storage-persister

npm i https://pkg.pr.new/@tanstack/query-sync-storage-persister@10510

@tanstack/react-query

npm i https://pkg.pr.new/@tanstack/react-query@10510

@tanstack/react-query-devtools

npm i https://pkg.pr.new/@tanstack/react-query-devtools@10510

@tanstack/react-query-next-experimental

npm i https://pkg.pr.new/@tanstack/react-query-next-experimental@10510

@tanstack/react-query-persist-client

npm i https://pkg.pr.new/@tanstack/react-query-persist-client@10510

@tanstack/solid-query

npm i https://pkg.pr.new/@tanstack/solid-query@10510

@tanstack/solid-query-devtools

npm i https://pkg.pr.new/@tanstack/solid-query-devtools@10510

@tanstack/solid-query-persist-client

npm i https://pkg.pr.new/@tanstack/solid-query-persist-client@10510

@tanstack/svelte-query

npm i https://pkg.pr.new/@tanstack/svelte-query@10510

@tanstack/svelte-query-devtools

npm i https://pkg.pr.new/@tanstack/svelte-query-devtools@10510

@tanstack/svelte-query-persist-client

npm i https://pkg.pr.new/@tanstack/svelte-query-persist-client@10510

@tanstack/vue-query

npm i https://pkg.pr.new/@tanstack/vue-query@10510

@tanstack/vue-query-devtools

npm i https://pkg.pr.new/@tanstack/vue-query-devtools@10510

commit: 85317f2

@TkDodo TkDodo merged commit ea4497e into TanStack:main Apr 25, 2026
8 checks passed
@github-actions github-actions Bot mentioned this pull request Apr 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Type error when using experimental_createPersister with a queryFn that has an argument

2 participants