Skip to content

fix: type useQuery's data from select, as TanStack does - #2

Merged
julien1619 merged 3 commits into
mainfrom
fix/use-query-select-type
Oct 9, 2026
Merged

julien1619 merged 3 commits into
mainfrom
fix/use-query-select-type

Conversation

@julien1619

Copy link
Copy Markdown
Member

Problem

The generated useQuery typed its options as Omit<UseQueryOptions, 'queryKey' | 'queryFn'>. UseQueryOptions is a MaybeRef<…>, and Omit over that union keeps no key, so:

  • select received an implicit any;
  • data stayed typed as the raw payload, whatever select returned.

Change

  • useQuery is generic in TData (default: the endpoint's data). Its options are the plain variant of UseQueryOptions<_QD, DefaultError, TData, _QD, QueryKey>, so TanStack infers TData from select exactly like its own useQuery. A select expecting another input than the payload is refused.
  • fetchQuery / ensureQueryData get FetchQueryOptions / EnsureQueryDataOptions on the endpoint's data (no select, as neither applies one).
  • Every GET method goes through a single _get fetch; _QD is its resolved type, with or without an output schema.
  • enabled and queryKey behave as before.

Tests

playground/app.vue pins the types (checked by npm run test:types):

  • no select → data is the payload, not any;
  • select → data is the selected type, not any;
  • a select with a wrong input type → error;
  • an endpoint without options infers the same way.

Against the previous generator, these checks fail with 4 errors. CI now runs test:types, which previously ran only locally.

Verified on a consumer app (Mesalia booking): replacing a hand-rolled TanStack query by the generated useQuery(o, { select }) typechecks with the selected types.

🤖 Generated with Claude Code

julien1619 and others added 3 commits October 9, 2026 10:20
The generated `useQuery` took `queryOptions?: Omit<UseQueryOptions, …>`.
`UseQueryOptions` is a `MaybeRef<…>`, and `Omit` over that union keeps no key
at all, so the options were neither typed nor tied to the endpoint: `select`
received an implicit `any`, and `data` stayed typed as the raw payload
whatever `select` returned.

`useQuery` is now generic in `TData`, defaulting to the endpoint's data, and
its options are the plain object variant of
`UseQueryOptions<_QD, DefaultError, TData, _QD, QueryKey>`. TanStack infers
`TData` from `select` as its own `useQuery` does, and a `select` expecting
another input than the payload is refused. `fetchQuery` and `ensureQueryData`
get their own option types, on the endpoint's data, without `select`.

Every GET method now goes through one `_get` fetch, whose resolved type is
the data type, with or without an output schema.

The playground pins these types, and CI now runs `test:types`, which used to
run only locally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Node 20 lacks Object.groupBy, which eslint-flat-config-utils calls: lint has failed on main since July.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The root route (/api/) has no segment, so its key was emitted with a hole ([, ...query]) and, without a query, was [], the placeholder every disabled query shares. It now starts with an empty string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@julien1619
julien1619 merged commit 363fc93 into main Oct 9, 2026
2 checks passed
@julien1619
julien1619 deleted the fix/use-query-select-type branch October 9, 2026 08:36
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.

1 participant