Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript errors when using exported queryOptions factory in @tanstack/react-query 5.62.8 #8453

Closed
hylickipiotr opened this issue Dec 18, 2024 · 14 comments
Labels

Comments

@hylickipiotr
Copy link

Describe the bug

When using the factory queryOptions and exporting the result, TypeScript errors appear:

Exported variable 'shopsQuery' has or is using name 'dataTagErrorSymbol' from external module "/node_modules/@tanstack/query-core/build/legacy/hydration-DiTAi-4H" but cannot be named. (ts4023)

Exported variable 'shopsQuery' has or is using name 'dataTagSymbol' from external module "/node_modules/@tanstack/query-core/build/legacy/hydration-DiTAi-4H" but cannot be named. (ts4023)

These errors occur in every instance where I export the result of queryOptions. Removing the export resolves the issue, but that isn't an acceptable workaround.

Your minimal, reproducible example

https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAbzgRwK4FMoE8DyYbAQB2AznAL5wBmUEIcARAAIwCGpbAxgNYD0U6VpxgBaNJiwMAsAChZnYiXgKoA4QEUM2PAUVwAvCi258hUgAoEsuEYkBpdFgBccANoByFWpjuAugBpZcgBKWTCZdAAPSFg4BQ44YCIAN1YAG2AAE00JHTMyQ3FtU0VLa1tsB2c3dyTUjMy-QJkQoA

Steps to reproduce

  1. Install the latest version of @tanstack/react-query (v5.62.8).
  2. Create and export a variable using queryOptions factory, e.g., export const shopsQuery = queryOptions(...);.
  3. Observe TypeScript errors as described.

Expected behavior

The queryOptions factory should allow exporting without triggering TypeScript errors.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

  • OS [Windows, Linux]

Tanstack Query adapter

react-query

TanStack Query version

v5.62.8

TypeScript version

v5.7.2

Additional context

No response

@codelonesomest
Copy link

I got the same problem as well in v5.62.8 but no problem in v5.62.7.

@arnoud-dv
Copy link
Collaborator

@TkDodo @Nick-Lucas I'm getting comments about typing problems since v5.62.7 / #8394 on Angular too, e.g.: #6293 (comment)

@Nick-Lucas
Copy link
Contributor

@TkDodo @Nick-Lucas I'm getting comments about typing problems since v5.62.7 / #8394 on Angular too, e.g.: #6293 (comment)

I've seen this too in the tRPC codebase, returning a datatagged thing (query key, query options, etc) shows a portability error unless you explicitly type the return - as a workaround that's the solution

I'm not entirely sure right now how to prevent it but I know it's a common problem in libs

@juliusmarminge we've solved this for tRPC before, right?

@juliusmarminge
Copy link
Contributor

@juliusmarminge we've solved this for tRPC before, right?

Did you create some new types that aren't exported from a public entrypoint? That's usually a primary cause.

But RQ is, and never will be with the current behaviors in TypeScript, not fully portable since it relies on @tanstack/query-core internals that users doesn't automatically install. This is the case for all libs that relies on a "core" package. A fix for those cases is that the user installs both libs explicitly which makes it easier for TypeScript to discover the scanned paths when emitted the declaration files.

@Nick-Lucas
Copy link
Contributor

Nick-Lucas commented Dec 23, 2024

Interestingly dataTagSymbol has been there for a year, so it's weird that one's causing a problem now. dataTagErrorSymbol is newish but since a few releases before 5.62.7

Perhaps the root is is simply that queryOptions is now more correctly typed and so call sites where this wasn't an issue before are now an issue?

@juliusmarminge
Copy link
Contributor

juliusmarminge commented Dec 23, 2024

Are all types used for data tags and queryOptions exported from the main RQ entrypoint? Are any re-exports from core package?

EDIT: Ah the symbols are from core package. Can they not be defined and exported in the framework package? I think that might help TS discover them more easily. IIRC last time I looked at queryOptions stuff all types are in each framework package so why can't the data tags also be there?

Image

@Nick-Lucas
Copy link
Contributor

Nick-Lucas commented Dec 23, 2024

In this case no these symbols aren't exported by either query-core or rq/angular directly, I will play with an MR which changes this as we already have a reproduction in tRPC that I can test against

Some workarounds in the mean-time:

  • If you have an application then you may not need tsconfig to have compilerOptions.declaration: true - setting it false should squash the error
  • If you have a library then explicitly defining your return types should squash the issue (also true in apps, but more annoying)

@TkDodo
Copy link
Collaborator

TkDodo commented Dec 23, 2024

If you have an application then you may not need tsconfig to have compilerOptions.declaration: true - setting it false should squash the error

definitely need declaration: true for monorepos

In this case no these symbols aren't exported by either query-core or rq/angular directly, I will play with an MR which changes this as we already have a reproduction in tRPC that I can test against

we can export the symbols from the core, no problem.

Can they not be defined and exported in the framework package?

no, because core things in the queryClient need them, too (see queryClient.getQueryData)

@TkDodo TkDodo added the types label Dec 23, 2024
@TkDodo
Copy link
Collaborator

TkDodo commented Dec 23, 2024

In this case no these symbols aren't exported by either query-core or rq/angular directly

@Nick-Lucas as far as I can see, we do export the symbols:

export declare const dataTagSymbol: unique symbol
export declare const dataTagErrorSymbol: unique symbol
export declare const unsetMarker: unique symbol

// Types
export * from './types'

I can also import them from @tanstack/react-query directly.

@omridevk
Copy link

same here

@Nick-Lucas
Copy link
Contributor

I can also import them from @tanstack/react-query directly.

Yes that's what I want to ensure is happening, hard to trace through barrel files though, back online now so I'll take a look

@Nick-Lucas
Copy link
Contributor

Nick-Lucas commented Dec 23, 2024

Okay so some investigation against tRPC's new client where I have observed the issue when returning queryOptions()

  • Firstly dataTagSymbol and dataTagErrorSymbol are indeed exported by react-query via barrel so no issues there
  • Adding @tanstack/query-core as a dependency to the project does not fix it
  • Importing dataTagSymbol and dataTagErrorSymbol from react-query does make the error go away, comes with the need to ignore unused dependencies errors in eslint but I think this is the easiest workaround for now

I noticed the way symbols are declared is different from tRPC though, and switching over does seem to work, though I don't really know what the difference is

#8468

Image

No error:
Image

ChatGPT (Link to chat) informs me that the declare keyword is just a declaration without an implementation, but the tRPC way actually creates a concrete symbol which we can then draw a type declaration from. That may explain why typescript isn't behaving as people describe, the type needs to have an implementation to be inferable via a library later - I'd love to understand this more but I don't

@beaussan
Copy link

Hey folks, i don't think this is properly fixed. The output d.ts is using a symbol without being imported and thus, resulting into incorrect d.ts files

Given this input:

import { queryOptions } from "@tanstack/react-query"

export const exported = queryOptions({
  queryKey: ['invalid'],
})

Here is the d.ts output:

export declare const exported: import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<unknown, Error, unknown, string[]>, "queryFn"> & {
    queryFn?: import("@tanstack/react-query").QueryFunction<unknown, string[], never> | undefined;
} & {
    queryKey: string[] & {
        [dataTagSymbol]: unknown;
        [dataTagErrorSymbol]: Error;
    };
};

And both symbols are not imported :/

A minimal reproduction can be looked at https://tsplay.dev/w2O6bN

A reproduction can be looked at TanStack/router#3078 , then running pnpm install and then pnpm nx run router-monorepo-react-query:dev

Output per version, regarding the mono example on tanstack/router

Input:

import { queryOptions } from '@tanstack/react-query'
import { fetchPost } from './posts'

export const postQueryOptions = (postId: string) =>
  queryOptions({
    queryKey: ['posts', { postId }],
    queryFn: () => fetchPost(postId),
  })

React Query 5.62.7 output:

export declare const postQueryOptions: (postId: string) => import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<import('./posts').PostType, Error, import('./posts').PostType, import('@tanstack/react-query').QueryKey>, "queryFn"> & {
    queryFn?: import('@tanstack/react-query').QueryFunction<import('./posts').PostType, import('@tanstack/react-query').QueryKey, never> | undefined;
} & {
    queryKey: import('@tanstack/react-query').DataTag<import('@tanstack/react-query').QueryKey, import('./posts').PostType>;
};

React Query 5.62.8 output (no d.ts at all):

src/postQueryOptions.tsx:4:14 - error TS4023: Exported variable 'postQueryOptions' has or is using name 'dataTagErrorSymbol' from external module "/Users/nicolasbeaussart-hatchuel/work/perso/git/tanstack/router/node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/hydration-DiTAi-4H" but cannot be named.

4 export const postQueryOptions = (postId: string) =>
               ~~~~~~~~~~~~~~~~
src/postQueryOptions.tsx:4:14 - error TS4023: Exported variable 'postQueryOptions' has or is using name 'dataTagSymbol' from external module "/Users/nicolasbeaussart-hatchuel/work/perso/git/tanstack/router/node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/hydration-DiTAi-4H" but cannot be named.

4 export const postQueryOptions = (postId: string) =>

That was fixed with #8468

However, with react Query 5.62.9, compile dts but type check is not passing, here is the d.ts:

export declare const postQueryOptions: (postId: string) => import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<import('./posts').PostType, Error, import('./posts').PostType, (string | {
    postId: string;
})[]>, "queryFn"> & {
    queryFn?: import('@tanstack/react-query').QueryFunction<import('./posts').PostType, (string | {
        postId: string;
    })[], never> | undefined;
} & {
    queryKey: (string | {
        postId: string;
    })[] & {
        [dataTagSymbol]: import('./posts').PostType;
        [dataTagErrorSymbol]: Error;
    };
};

However, both symbol are assumed global, but aren't defined globally

@Nick-Lucas
Copy link
Contributor

That's really unusual and I'm not sure what could be wrong here

Couldn't get the tsplayground to reproduce, but the router PR is definitely not behaving how I would expect

> pnpm nx run @router-mono-react-query/post-query:build

Image

My best idea was the types needed explicitly exporting from query-core and react-query, but that hasn't helped: https://github.com/TanStack/query/pull/8481/files

tsconfig's skipLibCheck will hide the error though I understand that's not right for many projects

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants