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

Open
hylickipiotr opened this issue Dec 18, 2024 · 16 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

arnoud-dv commented Dec 23, 2024

@TkDodo @Nick-Lucas I'm getting comments about typing problems since v5.62.8 / #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
Collaborator

@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
Collaborator

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

@beaussan
Copy link

beaussan commented Dec 29, 2024

Couldn't get the tsplayground to reproduce

You can see it on the ts playground in the link I've mentioned tsplay.dev/w2O6bN, and then go to the d.ts tab on the right

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

That could be a workaround, but that dosen't change the fact that the symbol is assumed global, without a global definition :/

What is weird is that previous to 5.62.8, the query key is using a generic

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>;
};

where as post 5.62.9, the query key type is computed (instead of using the generic), resulting in wrong reference

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;
    };
};

So I don't know what change in #8394 is making the DataDat not being used via the generic and instead resolving it, that is causing the issue here

@Nick-Lucas
Copy link
Contributor

Nick-Lucas commented Dec 29, 2024

Done some more looking into this and honestly I'm lost.

It makes sense why [dataTagErrorSymbol]: Error; couldn't be [import(...).dataTagErrorSymbol]: Error; because it's a value and import() returns a promise

But deciding to inline and producing invalid code just makes it seem like a typescript bug. Why not continue to reference the generic import if it can't be inlined correctly?

@arnoud-dv arnoud-dv reopened this Jan 2, 2025
pmmm114 added a commit to pmmm114/react-example-01 that referenced this issue Feb 17, 2025
- 신규버전부터 key에 대한 추론값 이슈

* TanStack/query#8453
pmmm114 added a commit to pmmm114/react-example-01 that referenced this issue Feb 21, 2025
[ business-logic ] chore: zustand, react-query 라이브러리 추가
- fetch 및 상태 관리를 위해 @tanstack/react-query
- 전역상태관리를 위해 zustand
- 데이터 불변성 유지를 위해 Immer

[ business-logic ] feat: NFT 쿼리 및 타입 정의
- NFT 관련 무한 스크롤 쿼리 구현 (Top Banner, Scroll List)
- React Query 무한 스크롤 옵션 및 쿼리 키 설정
- 메인 페이지 초기 데이터 fetching 로직 추가
- NFT 관련 타입 정의

[ business-logic ] feat: Zustand 메인 스토어 및 타입 정의
- 메인 페이지 상태 관리를 위한 Zustand 스토어 생성
- 탭 상태 및 상태 변경 액션 정의
- Immer 미들웨어를 사용한 불변성 유지
- 타입 안전성을 위한 타입 정의

[ business-logic ] feat: Main 페이지 데이터 페칭, 스켈레톤 UI 구현
- Top NFT섹션 스켈레톤 UI 추가
- 데이터 페칭 로직 추가

[ business-logic ] feat: Add React Query DevTools for development debugging

[ business-logic ] refactor: LazyImage 컴포넌트 스켈레톤 UI Wrapper 추가
- 스켈레톤 UI에 루트 클래스명 적용
- 스켈레톤 로딩 시 래퍼 div 추가로 스타일링 유연성 개선

[ business-logic ] feat: VirtualScroller 무한 스크롤 기능 추가 ( 데이터페칭 )
- 무한 스크롤 상태 타입 정의 (infiniteScrollStatus)
- 마지막 아이템 감지 시 다음 페이지 데이터 로드 로직 구현
- 타입 파일 분리로 코드 구조화

[ business-logic ] refactor: Main, Sub 페이지 스켈레톤 UI 및 데이터 페칭 로직 개선
- 메인/서브 페이지 스켈레톤 UI 로직 리팩토링
- 데이터 로딩 상태에 따른 null 데이터 처리
- 무한 스크롤 및 데이터 페칭 상태 관리 개선
- 타입 정의 및 컴포넌트 로직 최적화

[ business-logic ] feat: TypeScript 유형 추출을 위한 ArrayItem 유틸리티 유형 추가
- 배열에서 요소 유형을 추출하기 위한 새로운 유틸리티 유형
- 배열 항목 유형을 추론하는 유형 안전 방법을 제공

[ business-logic ] bugfix: react-query 타입 문제
- 신규버전부터 key에 대한 추론값 이슈
* TanStack/query#8453

[ business-logic ] chore: Disable react-hooks/exhaustive-deps ESLint rule
- Temporarily turn off exhaustive-deps rule to suppress warnings
- Allows more flexibility in dependency management for hooks

[ business-logic ] refactor: Signal 옵션 추가 및 쿼리키 옵션 수정
- 요청 취소를 활성화하기 위해 API 호출에 AbortSignal 지원 추가
- 더 나은 캐싱을 위해 무한 스크롤 목록 쿼리 키에 카테고리 포함
- useFetchMainPageInit에서 하드코딩된 페이지 매개변수 제거
- 쿼리 기능 유형의 안전성 및 유연성 향상

[ business-logic ] refactor: 메인 템플릿에서 무한 스크롤 및 데이터 가져오기 개선
- VirtualScroller 업데이트
- 무한스크롤 로딩 및 스켈레톤 UI를 지원하도록 메인템플릿 수정
- NFT 항목에 대한 데이터 렌더링 및 유형 관리 간소화

[ business-logic ] refactor: 이미지 생성기 seed parameter 추가

[ business-logic ] refactor: NFT카테고리 무한 스크롤 영역 gcTime 수정
- 0으로 설정
* 추후 고도화된 요구사항으로 변경 예정
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