query icon indicating copy to clipboard operation
query copied to clipboard

[vue-query]: Fresh Vue3 project + Tanstack - Typescript errors, This is likely not a portable.

Open cadriel opened this issue 2 years ago • 33 comments

Describe the bug

With a fresh Vue3 installation with @tanstack/vue-query installed - VSCode produces typescript errors, as seen in the screenshot.

It's not clear to me if this is an issue with tanstack-query, vue3 - or typescript. There seems to be various issues around that suggest it might be any of them.

Its worth noting that the project still runs and produces expected results.

tanstack/vue-query does not have this issue on V4. It only occurs after moving to V5.

Your minimal, reproducible example

https://github.com/cadriel/tanstack-query-issue

Steps to reproduce

  1. Clone the example project. https://github.com/cadriel/tanstack-query-issue
  2. Open the project in VSCode - ensure you've installed and configured the Vue dev tools (Volar, etc..)
  3. See the error as per the screenshot above.

Expected behavior

I'd expect to not see any errors in VSCode, and for the types to be correctly inferred.

How often does this bug happen?

Every time

Screenshots or Videos

Screenshot 2023-11-06 at 10 38 54 AM

Platform

macOS, VSCode.

Tanstack Query adapter

vue-query

TanStack Query version

V5+

TypeScript version

V5.2.2 (as per npm create vue@latest)

Additional context

No response

cadriel avatar Nov 06 '23 16:11 cadriel

Some google results suggest not using pnpm - the provided example specifically rules this out by not using pnpm.

cadriel avatar Nov 06 '23 16:11 cadriel

This has something to do with module resolution. Adding "moduleResolution": "node", to tsconfig.app.json fixes the issue. Also just importing type UseQueryReturnType without using it fixes the issue as well. But that is a workaround. I will try to figure out why this happens.

DamianOsipiuk avatar Nov 06 '23 22:11 DamianOsipiuk

Yes, you can add the type manually for the example. However, as soon as you add any complexity (mutations, etc..) - then it becomes very cumbersome to figure out what types to import.

I couldn't figure out what types to import at all for some circumstances.

The moduleResolution suggestion may cause other issues.

Ideally there should be no other requirements. Thanks for looking into this further.

cadriel avatar Nov 06 '23 23:11 cadriel

I would consider this a showstopper, this seems like an extremely big issue in actually using vue-query

piotrpalek avatar Nov 13 '23 17:11 piotrpalek

Seems to be an issue with multiple packages, the same problem occurs with @tanstack/react-query since V5 when "declaration": true is set:

Screenshot 2023-11-14 091338

We use query in our core-lib, switching to "moduleResolution": "node" fixes the error in the editor, but produces wrong .d.ts files later on.

With V4 the correct types looked like: export declare const useTest: import("@tanstack/react-query").UseMutationResult<string, Error, void, unknown>;

With V5 the types are now: export declare const useTest: import("@tanstack/react-query/build/legacy/types").UseMutationResult<string, Error, void, unknown>; which leads to errors in the consuming project.

thomasrde avatar Nov 14 '23 08:11 thomasrde

The declaration: true comment above may provide a hint. There were a lot of upstream dependencies that required updates in order to support Typescript changes. There was a bit of turmoil for a month or two. It might also be related to Vite and browser module resolution that bought about those updates.

In any case, vue-query@v5 is in an unusable state for us because of this.

@DamianOsipiuk You may want to consider increasing priority if this affects multiple packages.

cadriel avatar Nov 14 '23 15:11 cadriel

Just to give some update on this.

I did not figure out any good fix for this.
The most relevant comment i could find on this is https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189

What this means is if that you are re-exporting vue-query in your lib composables leveraging type inference, you need to at least re-export types from vue-query as it's transitive dependency of your package.

This should fix most of the issues, but i would appreciate input from any TS wizard if there is a better way to solve this.

@Andarist @mattpocock - TS wizards assemble... 🙈

DamianOsipiuk avatar Dec 19 '23 22:12 DamianOsipiuk

I’ll take a look in an hour or so. I know what can usually be done when it comes to this error

Andarist avatar Dec 19 '23 22:12 Andarist

I've done a quick analysis locally and i strongly believe that it's caused by tsup mangling~ (and renaming) exports in the declaration files. Instead of exporting UseQueryReturnType directly from useQuery-d58edace.d.ts and exporting it under the same name in index.d.ts, it exports it like this UseQueryReturnType as b and reexports it from index.d.ts like this: export { b as UseQueryReturnType } from './useQuery-d58edace.js';.

I think this might introduce an indirection that confuses TypeScript and it fails to recognize that this type is actually exported from @tanstack/vue-query. I patched declaration files locally to export UseQueryReturnType "directly" and the problem disappeared.

My recommendation would be to:

  • report this to tsup. I don't think this exports aliasing serves any real purpose in declaration files so I don't think it's worth doing
  • report this to TypeScript. I think that this is quite a basic aliasing case and that this could work better in TypeScript. A fix similar-ish to my https://github.com/microsoft/TypeScript/pull/56100 could fix this.

Andarist avatar Dec 19 '23 23:12 Andarist

@Andarist I'll add that this is not exclusive to vue-query, I believe this has to do with declaration inside the /build/modern/types as i've got an issue authoring a library that uses tanstack react-query and I've got the same issue, so this must be stemming from the query-core

I tried re-creating it, the dependencies work fine in a simple repo, issue happens in monorepos specifically.

Turning off declaration in tsconfig fixes the issue, but obviously as i'm authoring a library this is not a sufficient solution for me. So this does seem to be an issue with transitive dependency linking.

Running tsc --noEmit --traceResolutions yields following errors:

======== Module name '@typescript/lib-scripthost' was not resolved. ========
File '/Users/samuel/Coding/qman/query/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/package.json' does not exist according to earlier cached lookups.
File '/Users/samuel/Coding/qman/query/node_modules/.pnpm/[email protected]/node_modules/typescript/package.json' exists according to earlier cached lookups.
node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/hydration.d.cts:1:210 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("./queryClient-iw7Hbrkm.js")' call instead.
 
1 import { o as Mutation, n as Query, H as QueryOptions, ap as MutationOptions, b as QueryClient, al as MutationKey, p as MutationState, an as MutationMeta, q as QueryKey, l as QueryState, B as QueryMeta } from './queryClient-iw7Hbrkm.js';
                                                                                                                                                                                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/index.d.cts:1:2466 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("./queryClient-iw7Hbrkm.js")' call instead.
 
1 export { aB as CancelOptions, C as CancelledError, t as DataTag, D as DefaultError, aA as DefaultOptions, V as DefaultedInfiniteQueryObserverOptions, O as DefaultedQueryObserverOptions, aj as DefinedInfiniteQueryObserverResult, ac as DefinedQueryObserverResult, Y as FetchInfiniteQueryOptions, a3 as FetchNextPageOptions, a4 as FetchPreviousPageOptions, X as FetchQueryOptions, a6 as FetchStatus, z as GetNextPageParamFunction, G as GetPreviousPageParamFunction, A as InfiniteData, ae as InfiniteQueryObserverBaseResult, ag as InfiniteQueryObserverLoadingErrorResult, af as InfiniteQueryObserverLoadingResult, S as InfiniteQueryObserverOptions, ah as InfiniteQueryObserverRefetchErrorResult, ak as InfiniteQueryObserverResult, ai as InfiniteQueryObserverSuccessResult, K as InfiniteQueryPageParamsOptions, I as InitialDataFunction, J as InitialPageParam, a1 as InvalidateOptions, $ as InvalidateQueryFilters, as as MutateFunction, ar as MutateOptions, o as Mutation, M as MutationCache, d as MutationCacheNotifyEvent, f as MutationFilters, ao as MutationFunction, al as MutationKey, an as MutationMeta, e as MutationObserver, at as MutationObserverBaseResult, aw as MutationObserverErrorResult, au as MutationObserverIdleResult, av as MutationObserverLoadingResult, aq as MutationObserverOptions, ay as MutationObserverResult, ax as MutationObserverSuccessResult, ap as MutationOptions, p as MutationState, am as MutationStatus, E as NetworkMode, N as NoInfer, aE as NotifyEvent, aD as NotifyEventType, F as NotifyOnChangeProps, P as PlaceholderDataFunction, x as QueriesPlaceholderDataFunction, n as Query, Q as QueryCache, a as QueryCacheNotifyEvent, b as QueryClient, az as QueryClientConfig, g as QueryFilters, u as QueryFunction, w as QueryFunctionContext, q as QueryKey, y as QueryKeyHashFunction, B as QueryMeta, c as QueryObserver, a7 as QueryObserverBaseResult, a9 as QueryObserverLoadingErrorResult, a8 as QueryObserverLoadingResult, L as QueryObserverOptions, aa as QueryObserverRefetchErrorResult, ad as QueryObserverResult, ab as QueryObserverSuccessResult, H as QueryOptions, v as QueryPersister, l as QueryState, a5 as QueryStatus, _ as RefetchOptions, a0 as RefetchQueryFilters, R as Register, a2 as ResetOptions, Z as ResultOptions, aC as SetDataOptions, T as ThrowOnError, U as Updater, W as WithRequired, s as dataTagSymbol, h as hashKey, j as isCancelledError, i as isServer, k as keepPreviousData, m as matchQuery, r as replaceEqualDeep } from './queryClient-iw7Hbrkm.js';
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/infiniteQueryObserver.d.cts:1:342 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("./queryClient-iw7Hbrkm.js")' call instead.
 
1 import { D as DefaultError, A as InfiniteData, q as QueryKey, c as QueryObserver, ak as InfiniteQueryObserverResult, aG as ObserverFetchOptions, b as QueryClient, S as InfiniteQueryObserverOptions, aH as NotifyOptions, V as DefaultedInfiniteQueryObserverOptions, a3 as FetchNextPageOptions, a4 as FetchPreviousPageOptions, n as Query } from './queryClient-iw7Hbrkm.js';
                                                                                                                                                                                                                                                                                                                                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/queriesObserver.d.cts:1:156 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("./queryClient-iw7Hbrkm.js")' call instead.
 
1 import { ad as QueryObserverResult, b as QueryClient, L as QueryObserverOptions, aH as NotifyOptions, n as Query, q as QueryKey, c as QueryObserver } from './queryClient-iw7Hbrkm.js';
                                                                                                                                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
node_modules/.pnpm/@[email protected][email protected]/node_modules/@tanstack/react-query/build/modern/HydrationBoundary.d.cts:1:24 - error TS7016: Could not find a declaration file for module 'react'. '/Users/samuel/Coding/qman/query/node_modules/.pnpm/[email protected]/node_modules/react/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/react` if it exists or add a new declaration (.d.ts) file containing `declare module 'react';`
 
1 import * as React from 'react';
                         ~~~~~~~
 
node_modules/.pnpm/@[email protected][email protected]/node_modules/@tanstack/react-query/build/modern/isRestoring.d.cts:1:24 - error TS7016: Could not find a declaration file for module 'react'. '/Users/samuel/Coding/qman/query/node_modules/.pnpm/[email protected]/node_modules/react/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/react` if it exists or add a new declaration (.d.ts) file containing `declare module 'react';`
 
1 import * as React from 'react';
                         ~~~~~~~
 
node_modules/.pnpm/@[email protected][email protected]/node_modules/@tanstack/react-query/build/modern/QueryClientProvider.d.cts:1:24 - error TS7016: Could not find a declaration file for module 'react'. '/Users/samuel/Coding/qman/query/node_modules/.pnpm/[email protected]/node_modules/react/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/react` if it exists or add a new declaration (.d.ts) file containing `declare module 'react';`
 
1 import * as React from 'react';
                         ~~~~~~~
 
node_modules/.pnpm/@[email protected][email protected]/node_modules/@tanstack/react-query/build/modern/QueryClientProvider.d.cts:10:89 - error TS2503: Cannot find namespace 'JSX'.
 
10 declare const QueryClientProvider: ({ client, children, }: QueryClientProviderProps) => JSX.Element;
                                                                                           ~~~
 
node_modules/.pnpm/@[email protected][email protected]/node_modules/@tanstack/react-query/build/modern/QueryErrorResetBoundary.d.cts:1:24 - error TS7016: Could not find a declaration file for module 'react'. '/Users/samuel/Coding/qman/query/node_modules/.pnpm/[email protected]/node_modules/react/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/react` if it exists or add a new declaration (.d.ts) file containing `declare module 'react';`
 
1 import * as React from 'react';
                         ~~~~~~~
 
 
Found 9 errors in 8 files.
 
Errors  Files
     1  node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/hydration.d.cts:1
     1  node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/index.d.cts:1
     1  node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/infiniteQueryObserver.d.cts:1
     1  node_modules/.pnpm/@[email protected]/node_modules/@tanstack/query-core/build/modern/queriesObserver.d.cts:1
     1  node_modules/.pnpm/@[email protected][email protected]/node_modules/@tanstack/react-query/build/modern/HydrationBoundary.d.cts:1
     1  node_modules/.pnpm/@[email protected][email protected]/node_modules/@tanstack/react-query/build/modern/isRestoring.d.cts:1
     2  node_modules/.pnpm/@[email protected][email protected]/node_modules/@tanstack/react-query/build/modern/QueryClientProvider.d.cts:1
     1  node_modules/.pnpm/@[email protected][email protected]/node_modules/@tanstack/react-query/build/modern/QueryErrorResetBoundary.d.cts:1

You can find the entire paste here https://pastebin.com/NfJX8gsX

This would probably confirm what you referneced in your comment above, that this for some reason makes typescript detect the type export from the generated build js files, instead of the type declarations on .d.ts. This is causing resolution issues with the require syntax.

I also know this was not an issue in older monorepo projects using tanstack query, since I had one working fine, so must be caused by some of the type changes on your end.

If you need / want any more info let me know, i sadly didn't have time to do any patching / tinkering as this is a hobby project and I'm quite busy with work at the moment.

samuelhulla avatar Dec 21 '23 11:12 samuelhulla

that this for some reason makes typescript detect the type export from the generated build js files, instead of the type declarations on .d.ts.

I'd need a pointer as to where that happens - the log is, well, quite long and I lack a lot of context here. I just have investigated one concrete case here.

This is causing resolution issues with the require syntax.

This might potentially be a different issue - but hard to tell without seeing a repro case.

I also know this was not an issue in older monorepo projects using tanstack query, since I had one working fine, so must be caused by some of the type changes on your end.

Maybe the new release includes package.json#exports and your monorepo is using moduleResolution: nodenext (or similar)?


You can always fix those issues by using explicit type annotations. I have a plan to investigate this more on the TS side of things during the Christmas break - but either way, a fix in the compiler won't be released until at least TS 5.4 (in like 3 months since now or smth like that).

So I'd encourage the maintainers of this repo to investigate alternative solutions in the meantime. The "best" one would be to fix this in tsup since that would benefit everybody using that project.

Andarist avatar Dec 21 '23 12:12 Andarist

@Andarist I pushed the issue to git https://github.com/hulla-dev/qman/tree/feat/query

Specifically the issue occurs under /query/src/use.ts

I have both package.json#xports and moduleResolution: nodenext set up, but I haven't heard of this happening. Sorry to muddy the waters if this turns out to be something else. Feel free to take a look


EDIT: For people stuck with this issue: This most likely can be fixed by simply annotating a return type to your function, i.e.

function x() {
  return useQuery(...)
}

just needs an annotation - which by the way can even be explicitly inferred:

function x(): ReturnType<typeof useQuery> {
  return useQuery(...)
}

Obviously it's not ideal, but it's the cleanest workaround rather than messing up your tsconfig by turning off your declarations or enabling preserveSymlinks both of which have (likely, depending on your use-case) undesired side-effects

samuelhulla avatar Dec 21 '23 12:12 samuelhulla

@Andarist I pushed the issue to git https://github.com/hulla-dev/qman/tree/feat/query

Specifically the issue occurs under /query/src/use.ts

I have both package.json#xports and moduleResolution: nodenext set up, but I haven't heard of this happening. Sorry to muddy the waters if this turns out to be something else. Feel free to take a look

EDIT: For people stuck with this issue: This most likely can be fixed by simply annotating a return type to your function, i.e.

function x() {
  return useQuery(...)
}

just needs an annotation - which by the way can even be explicitly inferred:

function x(): ReturnType<typeof useQuery> {
  return useQuery(...)
}

Obviously it's not ideal, but it's the cleanest workaround rather than messing up your tsconfig by turning off your declarations or enabling preserveSymlinks both of which have (likely, depending on your use-case) undesired side-effects

This isn't a solution. It was also already mentioned in this thread; https://github.com/TanStack/query/issues/6318#issuecomment-1797018783

Yes, explicitly adding the annotation for a simple useQuery works - but it becomes infinitely more complex for mutations or any other more complex functions - making it not viable.

cadriel avatar Dec 22 '23 16:12 cadriel

I started to investigate this in TypeScript and rechecked the original repro. It turns out that removing the renames doesn't fix this - but a direct export of the type does. What I mean is that if this file would just type UseQueryReturnType<... and if this file would just export { UseQueryReturnType } from './useQuery-CPqkvEsh.js'; then it would work.

Andarist avatar Dec 23 '23 10:12 Andarist

Merry Christmas: https://github.com/microsoft/TypeScript/pull/56857

Andarist avatar Dec 23 '23 12:12 Andarist

@Andarist you're a wizard my man, great job and enjoy your holidays 🎄

samuelhulla avatar Dec 23 '23 20:12 samuelhulla

@hulla-dev the TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. issue should be fixed as of #6585. Please let me know if it still appears in a separate issue - I think it's unrelated to this.

lachlancollins avatar Dec 28 '23 20:12 lachlancollins

@DamianOsipiuk @Andarist thanks for the debugging on this so far. With tsup v8, it's introduced an experimentalDts option which uses @microsoft/api-extractor. I'm wondering if we might have better luck using this?

From what I can see, it merges most declaration into a _tsup-dts-rollup.d.ts file, then re-exports the relevant types from each declaration.

For example useQuery.d.ts looks like this:

export { useQuery_alias_1 as useQuery } from './_tsup-dts-rollup';
export { UseQueryOptions_alias_1 as UseQueryOptions } from './_tsup-dts-rollup';
export { UndefinedInitialQueryOptions } from './_tsup-dts-rollup';
export { DefinedInitialQueryOptions } from './_tsup-dts-rollup';
export { UseQueryReturnType_alias_1 as UseQueryReturnType } from './_tsup-dts-rollup';
export { UseQueryDefinedReturnType_alias_1 as UseQueryDefinedReturnType } from './_tsup-dts-rollup';

It does look like it's missing .js extensions, which I think are necessary. Also, as the name suggests, it's also experimental, but it is intended to fix issues with the original deprecated rollup-plugin-dts plugin.

lachlancollins avatar Dec 28 '23 20:12 lachlancollins

It works with latest v4 TypeScript and with "moduleResolution": "node". TypeScript V5 didnt work even when I tried suggested workarounds. But, in template, data is of type any, even if in script tag data shows the right Ref with type

Kretiss avatar Dec 29 '23 21:12 Kretiss

My PR has been merged so you should be able to start using [email protected] tomorrow if this is a big problem for you and if you are willing to use the nightly TS version.

@lachlancollins this experimentalDts looks like a promising workaround - since flat-bundling declarations should avoid this TS problem.

Andarist avatar Jan 09 '24 19:01 Andarist

@Andarist's fix does not seem to work for me. I have moduleResolution set to bundler. (this is in a react project but I think the issues are related) 🤔

todor-a avatar Jan 19 '24 15:01 todor-a

Please always try to share a repro case in a runnable form - either by providing a git repository to clone or a codesandbox. I can’t investigate what I can’t debug.

Andarist avatar Jan 19 '24 15:01 Andarist

Sure, sorry. I will try and put it together. Thank you for all you do in the TypeScript community :)

todor-a avatar Jan 19 '24 15:01 todor-a

@Andarist Thanks for your effort so far.

I've updated the original repro (https://github.com/cadriel/tanstack-query-issue) and upgraded to ts 5.4.0-dev however the issue remains.

Was there something else that needed to be adjusted?

cadriel avatar Jan 19 '24 18:01 cadriel

I just tested it out and it works. I'm almost sure that you have forgotten to use the workspace TS version (you can choose "Select TypeScript Version..." from the command palette. This is such a big annoyance when using VS Code - you have to do it in each project separately 🙈

Andarist avatar Jan 19 '24 18:01 Andarist

I just tested it out and it works. I'm almost sure that you have forgotten to use the workspace TS version (you can choose "Select TypeScript Version..." from the command palette. This is such a big annoyance when using VS Code - you have to do it in each project separately 🙈

You're 100% correct. I always forget this - but yeah, I selected the project version and the lint issues went away.

cadriel avatar Jan 19 '24 18:01 cadriel

i don't get it. is using typescript 5.4.0-dev or the latest 5.4.0-beta would help resolve the issue ?

petitkriket avatar Feb 01 '24 08:02 petitkriket

Using the beta should resolve the issue that I was able to diagnose and fix here. If the issue persist please share a repro case.

Andarist avatar Feb 01 '24 09:02 Andarist

sorry for the noise, switching the project to 5.4.0-beta and VSCode with CMD + P Select TypeScript Version... to the project version "solved" the issue, too bad it's not working with previous 5.3.0 though.

petitkriket avatar Feb 02 '24 10:02 petitkriket

Anyway, switching to the beta of TS isn't a good solution in case you have other dependencies that require lower version (like eslint-typescript).

extrem7 avatar Feb 06 '24 20:02 extrem7