Skip to content

modern useQuery: dataState includes "partial" for complex TVariables even when returnPartialData is false #13342

Description

@oceandrama

Issue Description

With modern hook signatures (TypeOverrides.signatureStyle: "modern"), useQuery incorrectly includes dataState: "partial" (and therefore DeepPartial<TData> for data) when TVariables is a large / complex input object — even if returnPartialData is omitted or set to the literal false.

With a small TVariables type, the same call correctly yields "complete" | "empty" | "streaming" only.

This matches the docs expectation that "partial" / DeepPartial should only appear when returnPartialData is enabled:
https://www.apollographql.com/docs/react/data/typescript#type-narrowing-data-with-datastate

Link to Reproduction

CodeSandbox (node template, @apollo/client@4.2.6): https://codesandbox.io/p/sandbox/fp82hz

Gist: https://gist.github.com/oceandrama/436975fa619df9b807195dcbae4f0894

npm i
npm run typecheck

simpleVars typechecks; complexVars fails with dataState including "partial" despite returnPartialData: false.

Note: TypeScript Playground ATA often fails to acquire @apollo/client types (complex package exports / peers), so prefer CodeSandbox/gist above.

Reproduction Steps

  1. Enable modern signatures via TypeOverrides.signatureStyle: "modern".
  2. Call useQuery with a TypedDocumentNode whose variables include a large optional input object (many nested optional fields), similar to a real GraphQL INPUT_OBJECT.
  3. Inspect dataState (e.g. with satisfies).
  4. Observe that "partial" is present even with returnPartialData: false.
  5. Compare with the same setup using a small variables type — "partial" is absent.

Suspected cause

In useQuery.ResultForOptions, "partial" is included unless:

OptionWithFallback<TOptions, DefaultOptions, "returnPartialData"> extends false

With complex TVariables, TypeScript appears to fail to keep a narrow inferred TOptions and falls back toward the full useQuery.Options constraint, where returnPartialData?: boolean. Then boolean extends false is false, so "partial" is always added.

Relevant sources (@apollo/client@4.2.6):

  • react/hooks/useQuery.d.tsResultForOptions / modern overload with circular TOptions extends Options & VariablesOption<...>
  • utilities/internal/types/OptionWithFallback.d.ts

A more default-safe check would be closer to extends true ? "partial" : never (only add "partial" when the option is known to be true). Tradeoff: a dynamic boolean flag would then be typed optimistically.

This is not specific to gql.tada / codegen — the same happens with a hand-written TypedDocumentNode and a large variables type.

@apollo/client version

4.2.6

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions