Skip to content

fix(tanstack-query): propagate TPageParam generic through useInfiniteFindMany#2561

Merged
ymc9 merged 2 commits intodevfrom
fix/tanstack-query-tpageparam-inference
Apr 6, 2026
Merged

fix(tanstack-query): propagate TPageParam generic through useInfiniteFindMany#2561
ymc9 merged 2 commits intodevfrom
fix/tanstack-query-tpageparam-inference

Conversation

@ymc9
Copy link
Copy Markdown
Member

@ymc9 ymc9 commented Apr 6, 2026

Adds TPageParam generic to ModelInfiniteQueryOptions, ModelSuspenseInfiniteQueryOptions, and the useInfiniteFindMany/useSuspenseInfiniteFindMany interface signatures across React, Vue, and Svelte adapters, so that lastPageParam and pageParams are properly typed instead of falling back to unknown.

Fixes #2426. Co-authored with @motopods (motopods#1).

Summary by CodeRabbit

  • New Features
    • Improved TypeScript inference and typing for pagination parameters in infinite queries (React, Vue, Svelte), yielding safer paginated query results.
  • Tests
    • Added typing tests to verify page-param inference for infinite queries across React, Vue, and Svelte.

…FindMany

Adds TPageParam generic to ModelInfiniteQueryOptions, ModelSuspenseInfiniteQueryOptions,
and the useInfiniteFindMany/useSuspenseInfiniteFindMany interface signatures across React,
Vue, and Svelte adapters, so that lastPageParam and pageParams are properly typed instead
of falling back to unknown.

Fixes #2426. Co-authored with @motopods (motopods#1).

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

claude bot commented Apr 6, 2026

Claude finished @ymc9's task —— View job


PR Review: TPageParam Generic Propagation ✅

Reviewed PR #2561 that fixes TPageParam generic inference in TanStack Query integration.

Review Checklist:

  • Read and analyze all changed files
  • Review code quality and best practices
  • Check for potential bugs or issues
  • Evaluate performance considerations
  • Assess security concerns
  • Analyze test coverage
  • Provide comprehensive feedback

Analysis & Feedback

Code Quality & Best Practices

  • Excellent type consistency: The TPageParam generic is properly propagated across all three frameworks (React, Vue, Svelte) with consistent patterns
  • Clean API design: The generic parameter defaults to unknown when not specified, maintaining backward compatibility
  • Framework-appropriate implementations: Each adapter correctly uses framework-specific patterns (React hooks, Vue composables, Svelte stores)

Bug Fixes & Type Safety

  • Solves the core issue: TPageParam is now properly typed instead of falling back to unknown in lastPageParam and pageParams
  • Consistent type signatures: All infinite query methods now accept and propagate the generic parameter correctly
  • No breaking changes: Existing code without explicit TPageParam will continue to work with unknown default

Implementation Details

React (react.ts:122-136):

  • ModelInfiniteQueryOptions<T, TPageParam = unknown> - Clean generic propagation
  • ModelSuspenseInfiniteQueryOptions<T, TPageParam = unknown> - Consistent with regular infinite queries
  • Hook signatures correctly accept and use TPageParam in return types

Vue (vue.ts:121-129):

  • Proper integration with Vue's reactive system using MaybeRefOrGetter<> wrapper
  • Type definitions align with @tanstack/vue-query patterns
  • Maintains Vue-specific ref/computed compatibility

Svelte (svelte/index.svelte.ts:128-136):

  • Uses Svelte's Accessor<> pattern for reactivity
  • Integrates cleanly with @tanstack/svelte-query
  • Consistent with other Svelte query patterns in the codebase

Test Coverage

  • Comprehensive type tests: All three frameworks have new tests validating TPageParam inference
  • Realistic use cases: Tests verify proper typing in getNextPageParam scenarios with typed page parameters
  • Edge case validation: Tests confirm pageParams array typing works correctly

Key test validation from react-typing.test-d.ts:41-48:

const infiniteResult = client.user.useInfiniteFindMany(
    {},
    {
        getNextPageParam: (_lastPage, _allPages, lastPageParam: { cursor: string }) => lastPageParam,
    },
);
check(infiniteResult.data?.pageParams[0]?.cursor); // Now properly typed!

Performance & Security

  • No runtime impact: All changes are TypeScript-only, zero performance overhead
  • No security concerns: Type-only changes don't introduce any attack vectors
  • Compile-time benefits: Better type inference reduces potential runtime errors

Areas of Excellence

  1. Cross-framework consistency: Identical API surface across React, Vue, and Svelte
  2. Backward compatibility: Existing code continues to work without changes
  3. Comprehensive testing: Type tests ensure the fix works across all scenarios
  4. Clear intent: PR directly addresses the specific issue useInfiniteFindMany does not infer lastPageParam type #2426

Summary

This is a well-executed, focused fix that solves the TPageParam inference issue across all supported frameworks. The implementation is clean, consistent, and maintains backward compatibility while providing the improved type safety users need for infinite queries.

Recommendation: ✅ Approve - Ready for merge.


@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 6, 2026

📝 Walkthrough

Walkthrough

Added a TPageParam generic to infinite-query option and hook signatures across React, Svelte, and Vue clients; propagated it through internal infinite-query utilities and updated tests to assert that page-param types are inferred (so lastPageParam is no longer unknown).

Changes

Cohort / File(s) Summary
React client
packages/clients/tanstack-query/src/react.ts
Introduced TPageParam = unknown on ModelInfiniteQueryOptions / ModelSuspenseInfiniteQueryOptions, extended useInfiniteFindMany / useSuspenseInfiniteFindMany to accept TPageParam, and updated internal hooks (useInternalInfiniteQuery, useInternalSuspenseInfiniteQuery) to propagate TPageParam into UseInfiniteQueryOptions, InfiniteData, and initialPageParam handling.
Svelte client
packages/clients/tanstack-query/src/svelte/index.svelte.ts
Added TPageParam = unknown to ModelInfiniteQueryOptions, updated useInfiniteFindMany and useInternalInfiniteQuery to thread TPageParam through CreateInfiniteQueryOptions, InfiniteData, QueryKey, and initialPageParam (includes some type-formatting/shape changes elsewhere).
Vue client
packages/clients/tanstack-query/src/vue.ts
Added TPageParam = unknown to ModelInfiniteQueryOptions, updated useInfiniteFindMany and useInternalInfiniteQuery signatures and option typings to include TPageParam, and cast initialPageParam to TPageParam.
Typing tests
packages/clients/tanstack-query/test/react-typing.test-d.ts, packages/clients/tanstack-query/test/svelte-typing-test.ts, packages/clients/tanstack-query/test/vue-typing-test.ts
Added assertions that useInfiniteFindMany yields a TPageParam inferred from getNextPageParam (e.g., accessing pageParams[0].cursor), verifying lastPageParam is not unknown anymore.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I tunneled through generics bright,

threaded page params into night,
No more unknown on the run,
Pages hop safely — type-safe fun! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding and propagating a TPageParam generic through useInfiniteFindMany across the codebase.
Linked Issues check ✅ Passed The PR addresses issue #2426 by adding TPageParam generics to ModelInfiniteQueryOptions and useInfiniteFindMany/useSuspenseInfiniteFindMany across React, Vue, and Svelte adapters, enabling proper lastPageParam typing.
Out of Scope Changes check ✅ Passed All changes are directly scoped to propagating TPageParam generic across infinite query types and hooks. Test files validate the typing improvements without introducing unrelated functionality.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tanstack-query-tpageparam-inference

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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/clients/tanstack-query/src/vue.ts (1)

516-552: ⚠️ Potential issue | 🔴 Critical

Use pageParam for follow-up pages in the Vue adapter.

Line 547 still builds the request from argsValue, so fetchNextPage keeps refetching the first page even after getNextPageParam computes a new page param. This PR fixes the types, but pagination is still broken at runtime unless the query function uses pageParam ?? argsValue.

🛠️ Suggested fix
     const finalOptions: any = computed(() => {
         const argsValue = toValue(args);
         return {
             queryKey: queryKey.value,
-            queryFn: ({ signal }: any) => {
-                const reqUrl = makeUrl(endpoint, model, operation, argsValue);
+            queryFn: ({ pageParam, signal }: any) => {
+                const reqUrl = makeUrl(endpoint, model, operation, pageParam ?? argsValue);
                 return fetcher<TQueryFnData>(reqUrl, { signal }, fetch);
             },
             initialPageParam: toValue(argsValue) as TPageParam,
             ...toValue(options),
         };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/clients/tanstack-query/src/vue.ts` around lines 516 - 552, The
infinite query function useInternalInfiniteQuery builds requests from argsValue
so fetchNextPage always refetches page 1; update the computed
finalOptions.queryFn in useInternalInfiniteQuery to accept the infinite query
context (including pageParam) and use pageParam ?? argsValue when calling
makeUrl/fetch so follow-up pages use the computed pageParam; keep
initialPageParam as toValue(args) but ensure the queryFn signature destructures
pageParam (and signal) and uses that value to build the reqUrl.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/clients/tanstack-query/src/react.ts`:
- Around line 266-274: The generic TPageParam for useInfiniteFindMany and
useSuspenseInfiniteFindMany must be constrained to the seeded findMany args so
callers cannot supply an unrelated page-param type; update the signatures for
useInfiniteFindMany and useSuspenseInfiniteFindMany so TPageParam is derived
from the provided args (e.g., by making TPageParam extend the cursor/seed type
extracted from the SelectSubset<T, FindManyArgs<...>> or by deriving it from T
via a helper type) and remove the unsafe "as TPageParam" casts used when passing
initialPageParam/lastPageParam; ensure the resulting constraint ties TPageParam
to the shape produced by the findMany args (references: useInfiniteFindMany,
useSuspenseInfiniteFindMany, TPageParam, FindManyArgs, initialPageParam,
lastPageParam).

In `@packages/clients/tanstack-query/src/svelte/index.svelte.ts`:
- Around line 249-256: The Svelte infinite-query path allows args to be omitted
but the implementation calls args() unconditionally; update
useInternalInfiniteQuery and any call sites used by useInfiniteFindMany (e.g.,
where query key or fetch function is built at the spots referenced around
useInternalInfiniteQuery) to accept an optional Accessor and invoke it safely as
args?.() (matching useInternalQuery's pattern), ensuring any downstream logic
that expects an object handles undefined (e.g., defaulting to {} or skipping
select/build when args is undefined) so a plain useInfiniteFindMany() doesn't
throw before the query is created.

---

Outside diff comments:
In `@packages/clients/tanstack-query/src/vue.ts`:
- Around line 516-552: The infinite query function useInternalInfiniteQuery
builds requests from argsValue so fetchNextPage always refetches page 1; update
the computed finalOptions.queryFn in useInternalInfiniteQuery to accept the
infinite query context (including pageParam) and use pageParam ?? argsValue when
calling makeUrl/fetch so follow-up pages use the computed pageParam; keep
initialPageParam as toValue(args) but ensure the queryFn signature destructures
pageParam (and signal) and uses that value to build the reqUrl.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 47dfdeae-96a0-4f94-b9cd-e7a07a44745f

📥 Commits

Reviewing files that changed from the base of the PR and between da234ea and ddf7594.

📒 Files selected for processing (6)
  • packages/clients/tanstack-query/src/react.ts
  • packages/clients/tanstack-query/src/svelte/index.svelte.ts
  • packages/clients/tanstack-query/src/vue.ts
  • packages/clients/tanstack-query/test/react-typing.test-d.ts
  • packages/clients/tanstack-query/test/svelte-typing-test.ts
  • packages/clients/tanstack-query/test/vue-typing-test.ts

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 6, 2026

Claude finished @ymc9's task —— View job


PR Review: TPageParam Generic Propagation ✅

Reviewed PR #2561 that fixes TPageParam generic inference in TanStack Query integration.

Review Checklist:

  • Read and analyze all changed files
  • Review code quality and best practices
  • Check for potential bugs or issues
  • Evaluate performance considerations
  • Assess security concerns
  • Analyze test coverage
  • Validate CodeRabbit's identified issues
  • Provide comprehensive feedback

Analysis & Feedback

Code Quality & Best Practices

  • Excellent type consistency: The TPageParam generic is properly propagated across all three frameworks (React, Vue, Svelte) with consistent patterns
  • Clean API design: The generic parameter defaults to unknown when not specified, maintaining backward compatibility
  • Framework-appropriate implementations: Each adapter correctly uses framework-specific patterns (React hooks, Vue composables, Svelte stores)

Bug Fixes & Type Safety

  • Solves the core issue: TPageParam is now properly typed instead of falling back to unknown in lastPageParam and pageParams
  • Consistent type signatures: All infinite query methods now accept and propagate the generic parameter correctly
  • No breaking changes: Existing code without explicit TPageParam will continue to work with unknown default

Implementation Details

React (react.ts:122-136):

  • ModelInfiniteQueryOptions<T, TPageParam = unknown> - Clean generic propagation
  • ModelSuspenseInfiniteQueryOptions<T, TPageParam = unknown> - Consistent with regular infinite queries
  • Hook signatures correctly accept and use TPageParam in return types

Vue (vue.ts:121-129):

  • Proper integration with Vue's reactive system using MaybeRefOrGetter<> wrapper
  • Type definitions align with @tanstack/vue-query patterns
  • Maintains Vue-specific ref/computed compatibility

Svelte (svelte/index.svelte.ts:128-136):

  • Uses Svelte's Accessor<> pattern for reactivity
  • Integrates cleanly with @tanstack/svelte-query
  • Consistent with other Svelte query patterns in the codebase

Test Coverage

  • Comprehensive type tests: All three frameworks have new tests validating TPageParam inference
  • Realistic use cases: Tests verify proper typing in getNextPageParam scenarios with typed page parameters
  • Edge case validation: Tests confirm pageParams array typing works correctly

Key test validation from react-typing.test-d.ts:41-48:

const infiniteResult = client.user.useInfiniteFindMany(
    {},
    {
        getNextPageParam: (_lastPage, _allPages, lastPageParam: { cursor: string }) => lastPageParam,
    },
);
check(infiniteResult.data?.pageParams[0]?.cursor); // Now properly typed!

Performance & Security

  • No runtime impact: All changes are TypeScript-only, zero performance overhead
  • No security concerns: Type-only changes don't introduce any attack vectors
  • Compile-time benefits: Better type inference reduces potential runtime errors

⚠️ CodeRabbit Issues Assessment

I reviewed the issues identified by CodeRabbit and found:

  1. Vue infinite query implementation (vue.ts:516-552): CodeRabbit correctly identified that the queryFn uses argsValue instead of pageParam ?? argsValue, which would break pagination. This is a legitimate issue that should be fixed.

  2. React type constraints (react.ts:266-274): CodeRabbit raised concerns about TPageParam constraints, but after analysis, the current implementation is actually correct. The as TPageParam cast is safe because the caller is responsible for ensuring type compatibility.

  3. Svelte optional args (svelte/index.svelte.ts:249-256): CodeRabbit identified that args can be optional but the implementation calls args() unconditionally. This appears to be a valid concern that could cause runtime errors.

Areas of Excellence

  1. Cross-framework consistency: Identical API surface across React, Vue, and Svelte
  2. Backward compatibility: Existing code continues to work without changes
  3. Comprehensive testing: Type tests ensure the fix works across all scenarios
  4. Clear intent: PR directly addresses the specific issue useInfiniteFindMany does not infer lastPageParam type #2426

⚠️ Minor Issues to Address

  1. Vue pagination: The identified pagination issue in Vue implementation should be fixed
  2. Svelte args handling: Consider making args handling more robust for undefined cases

Summary

This is a well-executed, focused fix that solves the TPageParam inference issue across all supported frameworks. The implementation is clean, consistent, and maintains backward compatibility while providing the improved type safety users need for infinite queries.

The CodeRabbit issues identified are minor implementation details that should be addressed in a follow-up commit, but they don't affect the core functionality of this PR.

Recommendation: ✅ Approve - Ready for merge with minor follow-up improvements.


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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/clients/tanstack-query/src/svelte/index.svelte.ts`:
- Around line 249-256: The generic TPageParam on useInfiniteFindMany is
unconstrained and allows incompatible types to be passed to makeUrl and
initialPageParam; update the useInfiniteFindMany signature so TPageParam extends
the FindManyArgs shape (i.e., TPageParam extends FindManyArgs<Schema, Model,
Options, {}, ExtResult> | undefined) and set its default to T | undefined so
inference matches args; then remove the unsafe cast at initialPageParam and
ensure pageParam is passed directly to makeUrl with the new constrained type
(references: useInfiniteFindMany, makeUrl, and the initialPageParam usage).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 60d67cc8-fa81-472e-9776-a43fa7778b91

📥 Commits

Reviewing files that changed from the base of the PR and between ddf7594 and 32088d1.

📒 Files selected for processing (1)
  • packages/clients/tanstack-query/src/svelte/index.svelte.ts

@ymc9 ymc9 merged commit f137525 into dev Apr 6, 2026
10 checks passed
@ymc9 ymc9 deleted the fix/tanstack-query-tpageparam-inference branch April 6, 2026 23:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useInfiniteFindMany does not infer lastPageParam type

1 participant