Skip to content

feat: add QueryKeyOptions type with strict generic to getXxxQueryKey functions#3424

Draft
Copilot wants to merge 7 commits intomainfrom
copilot/update-getquerykey-options
Draft

feat: add QueryKeyOptions type with strict generic to getXxxQueryKey functions#3424
Copilot wants to merge 7 commits intomainfrom
copilot/update-getquerykey-options

Conversation

Copy link
Contributor

Copilot AI commented Feb 20, 2026

  • Generate QueryKeyOptions<TOptions, TStrict> utility type with strict generic
  • Remove as cast — use explicit type arg createQueryKey<Options<T>>(...) instead
  • Fix CI type check failures: always pass explicit type arg to all createQueryKey calls (tanstack + pinia)
  • Fix pinia queryOptions.ts inline createQueryKey calls (when queryKeys.enabled = false)
  • Update snapshots and regenerate examples
Original prompt

This section details on the original issue you should resolve

<issue_title>getQueryKey should not enforce options</issue_title>
<issue_description>### Description

Continuing from what was mentioned in #980:

The query key function is strict for now, we could make it partial if needed

We would like to see support for non-strict version, as we may be invalidating a query in another part of the app that doesn't know of the callers options, but just wants the query to be invalidated

Obviously not a blocker as we can always just go to declaration and figure out how to do it manually but still</issue_description>

<agent_instructions>Improve our generated getXxxQueryKey() functions with the following changes:

  • update types such that each function accepts an optional strict boolean flag. It will default to true to preserve the current functionality
  • update the runtime implementation (if needed)

Example: previously, users might’ve had to supply the required parameters like this:

getPatientQueryKey({ path: { patient_id: "123" } })

With our changes, this should be a valid code that doesn’t throw any type errors:

getPatientQueryKey({ strict: false })
```</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@vercel
Copy link

vercel bot commented Feb 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hey-api-docs Ready Ready Preview, Comment Feb 20, 2026 4:39pm

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Feb 20, 2026

⚠️ No Changeset found

Latest commit: b9dbe59

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

…ict query invalidation

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copilot AI changed the title [WIP] Update getQueryKey to support non-strict options feat: add { strict: false } support to getXxxQueryKey functions Feb 20, 2026
Copilot AI requested a review from mrlubos February 20, 2026 11:45
@mrlubos
Copy link
Member

mrlubos commented Feb 20, 2026

@copilot This is wrong. Strict false shouldn't be bolted onto the type union for every query key. It should simply be a part of the options type. We might need a separate options type for TanStack Query/Pinia Colada on top of SDK. Strict false should also convert every parameter into optional, eg. if path parameters were required with foo and bar inside required too, strict false would make all optional, so it's possible to supply path parameters with only foo without bar complaining that it's missing. Your initial attempt doesn't support this at all, ie. it's completely wrong

… support and deep partials

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 20, 2026

@copilot This is wrong. Strict false shouldn't be bolted onto the type union for every query key. It should simply be a part of the options type. We might need a separate options type for TanStack Que...

Reworked in b5ab58f. Instead of bolting | { strict: false } onto each function, a QueryKeyOptions<TOptions> utility type is now generated once per file:

export type QueryKeyOptions<TOptions extends Options> = TOptions | ({
    [K in keyof Omit<TOptions, 'url'>]?: TOptions[K] extends object ? Partial<TOptions[K]> : TOptions[K]
} & {
    strict: false;
});

Required-data operations now use (options: QueryKeyOptions<Options<T>>) — the strict flag is part of the options type. When strict: false, all top-level fields are optional and nested object fields (path, query, body, headers) are also made partial, so getPatientQueryKey({ strict: false, path: { foo: "x" } }) works without bar being required.

Copilot AI changed the title feat: add { strict: false } support to getXxxQueryKey functions feat: add QueryKeyOptions type with strict: false support to getXxxQueryKey functions Feb 20, 2026
@mrlubos
Copy link
Member

mrlubos commented Feb 20, 2026

@copilot I'm surprised you didn't use strict as generic to narrow/expand the type – why? It also seems it's not possible to pass strict: true?

…g and strict: true support

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 20, 2026

@copilot I'm surprised you didn't use strict as generic to narrow/expand the type – why? It also seems it's not possible to pass strict: true?

Updated in 4440c4c. QueryKeyOptions now has TStrict extends boolean = true as a second generic, and query key functions for required-data operations expose the same generic so TypeScript infers it from the argument:

export type QueryKeyOptions<TOptions extends Options, TStrict extends boolean = true> =
    TStrict extends false
    ? { [K in keyof Omit<TOptions, 'url'>]?: TOptions[K] extends object ? Partial<TOptions[K]> : TOptions[K] } & { strict: false }
    : TOptions & { strict?: true };

export const callWithDefaultParametersQueryKey = <TStrict extends boolean = true>(
    options: QueryKeyOptions<Options<CallWithDefaultParametersData>, TStrict>
) => createQueryKey(...)

All three cases are now valid:

  • getXxxQueryKey({ path: { ... } }) — TStrict inferred as true
  • getXxxQueryKey({ strict: true, path: { ... } }) — explicit strict: true
  • getXxxQueryKey({ strict: false }) — TStrict inferred as false, all params optional

Copilot AI changed the title feat: add QueryKeyOptions type with strict: false support to getXxxQueryKey functions feat: add QueryKeyOptions type with strict generic to getXxxQueryKey functions Feb 20, 2026
@mrlubos
Copy link
Member

mrlubos commented Feb 20, 2026

@copilot type casting like this shouldn't be necessary:

export const typesQueryKey = <TStrict extends boolean = true>(options: QueryKeyOptions<Options<TypesData>, TStrict>) => createQueryKey('types', options as Options<TypesData>);

it should be possible to generate code like this:

export const typesQueryKey = <TStrict extends boolean = true>(options: QueryKeyOptions<Options<TypesData>, TStrict>) => createQueryKey('types', options);

…ic type arg

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 20, 2026

@copilot type casting like this shouldn't be necessary:

export const typesQueryKey = <TStrict extends boolean = true>(options: QueryKeyOptions<Options<TypesData>, TStrict>) => createQueryKey('...

Fixed in 5b41079. The cast is gone — createQueryKey now accepts Partial<Omit<TOptions, 'url'>> & { strict?: boolean } as its options parameter (which both branches of QueryKeyOptions satisfy), and the call uses an explicit type argument instead:

// before
createQueryKey('types', options as Options<TypesData>)

// after
createQueryKey<Options<TypesData>>('types', options)

@codecov
Copy link

codecov bot commented Feb 20, 2026

Codecov Report

❌ Patch coverage is 8.16327% with 45 lines in your changes missing coverage. Please review.
✅ Project coverage is 39.09%. Comparing base (b82d54b) to head (b9dbe59).

Files with missing lines Patch % Lines
...s/openapi-ts/src/plugins/@pinia/colada/queryKey.ts 9.09% 19 Missing and 1 partial ⚠️
...pi-ts/src/plugins/@tanstack/query-core/queryKey.ts 10.00% 17 Missing and 1 partial ⚠️
...enapi-ts/src/plugins/@pinia/colada/queryOptions.ts 0.00% 5 Missing ⚠️
...ns/@tanstack/query-core/v5/infiniteQueryOptions.ts 0.00% 1 Missing ⚠️
...rc/plugins/@tanstack/query-core/v5/queryOptions.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3424      +/-   ##
==========================================
- Coverage   39.16%   39.09%   -0.07%     
==========================================
  Files         474      474              
  Lines       17363    17403      +40     
  Branches     5246     5250       +4     
==========================================
+ Hits         6800     6804       +4     
- Misses       8490     8524      +34     
- Partials     2073     2075       +2     
Flag Coverage Δ
unittests 39.09% <8.16%> (-0.07%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mrlubos
Copy link
Member

mrlubos commented Feb 20, 2026

@copilot you need to update generated examples to make the CI pass: pnpm examples:generate

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 20, 2026

@copilot you need to update generated examples to make the CI pass: pnpm examples:generate

Done in d90da1f — ran pnpm examples:generate and committed the updated example files.

@mrlubos
Copy link
Member

mrlubos commented Feb 20, 2026

@copilot finally, we get to the CI checks testing types. And they fail. So your fix is not working. Make sure the CI checks would pass

…hecks

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 20, 2026

@copilot finally, we get to the CI checks testing types. And they fail. So your fix is not working. Make sure the CI checks would pass

Fixed in b9dbe59. The root cause was that TypeScript couldn't infer TOptions from Partial<Omit<TOptions, 'url'>>, causing query?: unknown in the return type.

Two fixes:

  1. queryKey.ts (both plugins)createQueryKeyLiteral now always passes an explicit type arg createQueryKey<Options<T>>(...), not just for required operations.
  2. pinia/colada/queryOptions.ts — moved typeData computation before the keyExpression block and added .generic(typeData) to inline createQueryKey calls (when queryKeys.enabled = false).

All examples now typecheck cleanly.

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.

getQueryKey should not enforce options

2 participants