Skip to content

feat(clients): add ExtResult support to TanStack Query hooks#2490

Merged
ymc9 merged 4 commits intozenstackhq:devfrom
genu:genu/tanstack-client-update
Mar 18, 2026
Merged

feat(clients): add ExtResult support to TanStack Query hooks#2490
ymc9 merged 4 commits intozenstackhq:devfrom
genu:genu/tanstack-client-update

Conversation

@genu
Copy link
Copy Markdown
Contributor

@genu genu commented Mar 17, 2026

Add type inference helpers to client-helpers enabling computed fields from plugins to be reflected in result types across React, Vue, and Svelte adapters.

Changes:

  • Add InferSchema, InferOptions, and InferExtResult type utilities to client-helpers
  • Update useClientQueries to accept a ClientContract type parameter instead of requiring separate schema + options generics
  • Simplify API by inferring schema, options, and ext-result types automatically
  • Update React, Vue, and Svelte sliced-client tests to use the new API surface

This enables better type inference when using plugins that extend query results with computed fields.

Summary by CodeRabbit

  • New Features

    • Propagates ExtResult-style extensions across React, Vue, and Svelte query clients and re-exports schema/options inference helpers.
    • Adds public types for ORM write actions, query error/info shapes, and cached query metadata.
  • Tests

    • Simplified sliced-client tests to derive client typings from instantiated clients rather than large inline generics.

Add InferSchema, InferOptions, and InferExtResult type utilities to client-helpers. Update React, Vue, and Svelte adapters to accept ClientContract type parameter, enabling computed fields from plugins to be reflected in result types. Simplify useClientQueries API by inferring schema and options from the client type. Update sliced-client tests to use new API surface.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2d63b67b-58b5-4d47-9640-0b9462fbf6d7

📥 Commits

Reviewing files that changed from the base of the PR and between 346799a and d5aead0.

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

📝 Walkthrough

Walkthrough

Adds InferSchema/InferExtResult/InferOptions and ORM/query helper types to client-helpers; threads an ExtResult generic through TanStack Query clients (React, Svelte, Vue), re-exports SchemaDef and new helpers, and updates typed tests to derive client types from instantiated ZenStackClient objects.

Changes

Cohort / File(s) Summary
Type Utilities
packages/clients/client-helpers/src/types.ts
Adds InferSchema, InferExtResult, InferOptions types; exports ORMWriteActions, ORMWriteActionType, QueryError, QueryInfo. Expands public typing for client contracts and ORM/query metadata.
TanStack Query — React
packages/clients/tanstack-query/src/react.ts
Re-exports InferExtResult, InferOptions, InferSchema, and SchemaDef. Threads ExtResult through ClientHooks, ModelQueryHooks, ModelMutationModelResult, per-model hook generics; updates useClientQueries/useModelQueries to accept `SchemaDef
TanStack Query — Svelte
packages/clients/tanstack-query/src/svelte/index.svelte.ts
Re-exports new helpers and SchemaDef; adds ExtResult generics across client hooks and mutation/result types; updates overloads and implementations of useClientQueries/useModelQueries to accept/infer ClientContract or SchemaDef.
TanStack Query — Vue
packages/clients/tanstack-query/src/vue.ts
Re-exports new helpers and SchemaDef; extends ClientHooks, ModelQueryHooks, ModelMutationModelResult, and per-model hook types with ExtResult; updates useClientQueries/useModelQueries signatures to accept `ClientContract
Typed tests
packages/clients/tanstack-query/test/react-sliced-client.test-d.ts, packages/clients/tanstack-query/test/svelte-sliced-client.test-d.ts, packages/clients/tanstack-query/test/vue-sliced-client.test-d.ts
Removes GetQueryOptions imports; refactors tests to instantiate ZenStackClient slices and pass typeof the client (e.g., typeof _slicedOps) to useClientQueries instead of large inline generic type arguments.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • merge dev to main (v3.4.0) #2414: Introduces the same InferSchema/InferExtResult/InferOptions and ORM-related type exports in client-helpers that are consumed and re-exported by the tanstack-query client changes.

Poem

🐰 I hopped through types with ears held high,

Wove ExtResult threads beneath the sky,
React, Svelte, Vue all got a stitch,
Clients now infer from a tiny switch,
A carrot-coded hop — hooray, type-ry!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 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 feature being added: ExtResult support to TanStack Query hooks, which enables better type inference for computed fields from plugins.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

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)

134-148: ⚠️ Potential issue | 🟠 Major

Preserve client-specific Options in the Vue mutation result type.

Line 142 still builds SimplifiedResult with QueryOptions<Schema> instead of the Options generic. That means mutateAsync resolves the sliced/narrowed type, but the returned mutation object's data is widened back to the generic schema shape.

Suggested fix
 export type ModelMutationModelResult<
     Schema extends SchemaDef,
     Model extends GetModels<Schema>,
     TArgs,
     Array extends boolean = false,
     Options extends QueryOptions<Schema> = QueryOptions<Schema>,
     ExtResult extends ExtResultBase<Schema> = {},
 > = Omit<
-    ModelMutationResult<SimplifiedResult<Schema, Model, TArgs, QueryOptions<Schema>, false, Array, ExtResult>, TArgs>,
+    ModelMutationResult<SimplifiedResult<Schema, Model, TArgs, Options, false, Array, ExtResult>, TArgs>,
     'mutateAsync'
 > & {
🤖 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 134 - 148, The
ModelMutationModelResult type currently constructs the Omit<>'d
ModelMutationResult using SimplifiedResult<..., QueryOptions<Schema>, ...>,
which widens the returned data; replace that QueryOptions<Schema> with the
generic Options so the client-specific Options generic is preserved (update the
SimplifiedResult type parameter in the Omit<> instantiation to use Options and
ensure any other occurrences in ModelMutationModelResult that reference
QueryOptions<Schema> are switched to Options, keeping mutateAsync's existing
signature aligned).
🧹 Nitpick comments (1)
packages/clients/tanstack-query/test/react-sliced-client.test-d.ts (1)

8-20: Consider an explicit ExtResult d.ts case here.

All of these Client types come from new ZenStackClient(...), so they only exercise the Schema + Options inference path; the fifth ClientContract generic stays at its default {}. That means this suite validates the new one-generic API shape, but not the computed-field inference this PR is adding. A small fixture with a non-empty ExtResult client type would lock that down, and it can be mirrored in the Vue/Svelte suites.

Also applies to: 31-41, 50-64, 77-85

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/clients/tanstack-query/test/react-sliced-client.test-d.ts` around
lines 8 - 20, The tests only exercise Schema+Options inference for new
ZenStackClient and omit the computed-field/ExtResult path; add a parallel TS
fixture that explicitly supplies a non-empty ExtResult (the fifth ClientContract
generic) to ZenStackClient so the type-checking covers computed-field inference
— e.g., create a const/alias using new ZenStackClient<Schema, Options, ?, ?, {
myComputedField: string }> or otherwise instantiate the client with an explicit
ExtResult type and assert the expected derived types; apply the same
explicit-ExtResult case to the other occurrences noted and mirror the change in
the Vue and Svelte test suites.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/clients/tanstack-query/src/vue.ts`:
- Around line 134-148: The ModelMutationModelResult type currently constructs
the Omit<>'d ModelMutationResult using SimplifiedResult<...,
QueryOptions<Schema>, ...>, which widens the returned data; replace that
QueryOptions<Schema> with the generic Options so the client-specific Options
generic is preserved (update the SimplifiedResult type parameter in the Omit<>
instantiation to use Options and ensure any other occurrences in
ModelMutationModelResult that reference QueryOptions<Schema> are switched to
Options, keeping mutateAsync's existing signature aligned).

---

Nitpick comments:
In `@packages/clients/tanstack-query/test/react-sliced-client.test-d.ts`:
- Around line 8-20: The tests only exercise Schema+Options inference for new
ZenStackClient and omit the computed-field/ExtResult path; add a parallel TS
fixture that explicitly supplies a non-empty ExtResult (the fifth ClientContract
generic) to ZenStackClient so the type-checking covers computed-field inference
— e.g., create a const/alias using new ZenStackClient<Schema, Options, ?, ?, {
myComputedField: string }> or otherwise instantiate the client with an explicit
ExtResult type and assert the expected derived types; apply the same
explicit-ExtResult case to the other occurrences noted and mirror the change in
the Vue and Svelte test suites.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1752260e-22ad-4ce9-a63c-81e82e0b0d3e

📥 Commits

Reviewing files that changed from the base of the PR and between 12aeb7b and a06004e.

📒 Files selected for processing (7)
  • packages/clients/client-helpers/src/types.ts
  • 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-sliced-client.test-d.ts
  • packages/clients/tanstack-query/test/svelte-sliced-client.test-d.ts
  • packages/clients/tanstack-query/test/vue-sliced-client.test-d.ts

Copy link
Copy Markdown
Member

@ymc9 ymc9 left a comment

Choose a reason for hiding this comment

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

Thanks for adding this @genu . It's a cleaner and better approach. I should have done it this way in the previous release. The only downside is you'll pull in the full typing of the ORM client to the client side (more type-level dependencies), which is probably fine.

Please check my few comments.

- Rename `Client` type parameter to `SchemaOrClient` in useClientQueries
- Remove `ExtResult` type parameter from hooks types (ClientHooks,
  ModelQueryHooks, ModelMutationModelResult, useModelQueries) since
  hooks are not subject to result extension; pass `{}` directly instead
- Clean up unused ExtResultBase and InferExtResult imports
@genu genu requested a review from ymc9 March 17, 2026 22:32
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/vue.ts`:
- Around line 138-145: The type ModelMutationResult currently hardcodes
QueryOptions<Schema> for the base mutation result which loses the generic
Options narrowing; update the base type so it uses the generic Options parameter
instead of QueryOptions<Schema> (i.e., replace the QueryOptions<Schema>
occurrence inside the Omit<SimplifiedResult<...>> with Options) so the overall
type and the mutateAsync signature both consistently reference Options
(affecting ModelMutationResult, SimplifiedResult and ModelMutationOptions
usage).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 83deb214-8e61-4520-bcc0-8c5de02a3f63

📥 Commits

Reviewing files that changed from the base of the PR and between a06004e and d6a7bc5.

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

…delResult

The base mutation result type was hardcoding QueryOptions<Schema> instead
of using the Options generic parameter, breaking consistency with React
and Svelte adapters.
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/vue.ts`:
- Around line 20-21: The Vue adapter is not threading the plugin-computed
extension type (InferExtResult) through its types and exports, causing plugin
fields to be lost; import and re-export InferExtResult alongside
InferOptions/InferSchema, then add an ExtResult generic (bounded by
InferExtResult) into the Vue-specific types that currently hardcode "{}" —
specifically update SimplifiedResult, SimplifiedPlainResult, all Find*Args
generics, and the return type of useClientQueries to accept and propagate
ExtResult so plugin-computed fields flow into query/mutation result types.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1313625a-59ba-4010-95b1-71958f5f1774

📥 Commits

Reviewing files that changed from the base of the PR and between d6a7bc5 and 346799a.

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

…cedures

The previous commit over-applied the review feedback — ExtResult was
removed from all hooks, but the reviewer intended it only for custom
procedure hooks. Regular model hooks should carry ExtResult typing for
plugin-computed field support.
@ymc9 ymc9 merged commit abae35a into zenstackhq:dev Mar 18, 2026
11 checks passed
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.

2 participants