diff --git a/docs/config.json b/docs/config.json index fc43b4ea86..542ecbd78a 100644 --- a/docs/config.json +++ b/docs/config.json @@ -58,9 +58,21 @@ "label": "Overview", "to": "framework/solid/overview" }, + { + "label": "Quick Start", + "to": "framework/solid/quick-start" + }, + { + "label": "Installation", + "to": "framework/solid/installation" + }, { "label": "Devtools", "to": "framework/solid/devtools" + }, + { + "label": "TypeScript", + "to": "framework/solid/typescript" } ] }, diff --git a/docs/framework/solid/devtools.md b/docs/framework/solid/devtools.md index a087d3ed79..530ccb81ee 100644 --- a/docs/framework/solid/devtools.md +++ b/docs/framework/solid/devtools.md @@ -7,8 +7,6 @@ Wave your hands in the air and shout hooray because Solid Query comes with dedic When you begin your Solid Query journey, you'll want these devtools by your side. They help visualize all of the inner workings of Solid Query and will likely save you hours of debugging if you find yourself in a pinch! -> Also note that you can use these devtools to observe queries, but **not mutations** (yet). - ## Install and Import the Devtools The devtools are a separate package that you need to install: @@ -29,7 +27,7 @@ You can import the devtools like this: import { SolidQueryDevtools } from '@tanstack/solid-query-devtools' ``` -By default, Solid Query Devtools are only included in bundles when `process.env.NODE_ENV === 'development'`, so you don't need to worry about excluding them during a production build. +By default, Solid Query Devtools are only included in bundles when `isServer === true` ([`isServer`](https://github.com/solidjs/solid/blob/a72d393a07b22f9b7496e5eb93712188ccce0d28/packages/solid/web/src/index.ts#L37) comes from the `solid-js/web` package), so you don't need to worry about excluding them during a production build. ## Floating Mode diff --git a/docs/framework/solid/installation.md b/docs/framework/solid/installation.md new file mode 100644 index 0000000000..c3660061b8 --- /dev/null +++ b/docs/framework/solid/installation.md @@ -0,0 +1,47 @@ +--- +id: installation +title: Installation +--- + +You can install Solid Query via [NPM](https://npmjs.com/), +or a good ol' ` +``` + +### Requirements + +Solid Query is optimized for modern browsers. It is compatible with the following browsers config + +``` +Chrome >= 91 +Firefox >= 90 +Edge >= 91 +Safari >= 15 +iOS >= 15 +Opera >= 77 +``` + +> Depending on your environment, you might need to add polyfills. If you want to support older browsers, you need to transpile the library from `node_modules` yourselves. diff --git a/docs/framework/solid/overview.md b/docs/framework/solid/overview.md index 5c504bce52..2b28496858 100644 --- a/docs/framework/solid/overview.md +++ b/docs/framework/solid/overview.md @@ -1,231 +1,137 @@ --- id: overview -title: Solid Query +title: Overview --- -The `@tanstack/solid-query` package provides a 1st-class API for using TanStack Query with SolidJS. +Solid Query is the official SolidJS adapter of TanStack Query that makes **fetching, caching, synchronizing and updating server state** in your web applications a breeze. -## Example +## Motivation -```tsx -import { - QueryClient, - QueryClientProvider, - createQuery, -} from '@tanstack/solid-query' -import { Switch, Match, For } from 'solid-js' +SolidJS has been gaining popularity as a fast, reactive, and declarative library for building user interfaces. It comes packed with a lot of features out of the box. Primitives like `createSignal`, `createStore` are great for managing client state. And, unlike other UI libraries, SolidJS has strong opinions about managing asynchronous data. The `createResource` API is a great primitive for handling server state in SolidJS apps. A `resource` is a special kind of signal that can be used to trigger `Suspense` boundaries when the data is in a loading state. -const queryClient = new QueryClient() +```tsx +import { createResource, ErrorBoundary, Suspense } from 'solid-js' -function Example() { - const query = createQuery(() => ({ - queryKey: ['todos'], - queryFn: fetchTodos, - })) +function App() { + const [repository] = createResource(async () => { + const result = await fetch('https://api.github.com/repos/TanStack/query') + if (!result.ok) throw new Error('Failed to fetch data') + return result.json() + }) return (
- - -

Loading...

-
- -

Error: {query.error.message}

-
- - {(todo) =>

{todo.title}

}
-
-
+
Static Content
+ {/* An error while fetching will be caught by the ErrorBoundary */} + Something went wrong!
}> + {/* Suspense will trigger a loading state while the data is being fetched */} + Loading...}> +
{repository().updated_at}
+
+ ) } -function App() { - return ( - - - - ) -} -``` - -## Available Functions - -Solid Query offers useful primitives and functions that will make managing server state in SolidJS apps easier. - -- `createQuery` -- `createQueries` -- `createInfiniteQueries` -- `createMutation` -- `useIsFetching` -- `useIsMutating` -- `useQueryClient` -- `QueryClient` -- `QueryClientProvider` - -## Important Differences between Solid Query & React Query +const root = document.getElementById('root') -Solid Query offers an API similar to React Query, but there are some key differences to be mindful of. - -- Arguments to `solid-query` primitives (like `createQuery`, `createMutation`, `useIsFetching`) listed above are functions, so that they can be tracked in a reactive scope. - -```tsx -// ❌ react version -useQuery({ - queryKey: ['todos', todo], - queryFn: fetchTodos, -}) - -// ✅ solid version -createQuery(() => ({ - queryKey: ['todos', todo], - queryFn: fetchTodos, -})) +render(() => , root!) ``` -- Suspense works for queries out of the box if you access the query data inside a `` boundary. +This is amazing! In a few lines of code, you can fetch data from an API and handle loading and error states. But, as your application grows in complexity, you will need more features to manage server state effectively. This is because **server state is totally different from client state**. For starters, server state: -```tsx -import { For, Suspense } from 'solid-js' +- Is persisted remotely in a location you do not control or own +- Requires asynchronous APIs for fetching and updating +- Implies shared ownership and can be changed by other people without your knowledge +- Can potentially become "out of date" in your applications if you're not careful -function Example() { - const query = createQuery(() => ({ - queryKey: ['todos'], - queryFn: fetchTodos, - })) - return ( -
- {/* ✅ Will trigger loading fallback, data accessed in a suspense boundary. */} - - {(todo) =>
{todo.title}
}
-
- {/* ❌ Will not trigger loading fallback, data not accessed in a suspense boundary. */} - {(todo) =>
{todo.title}
}
-
- ) -} -``` +Once you grasp the nature of server state in your application, **even more challenges will arise** as you go, for example: -- Solid Query primitives (`createX`) do not support destructuring. The return value from these functions is a store, and their properties are only tracked in a reactive context. +- Caching... (possibly the hardest thing to do in programming) +- Deduping multiple requests for the same data into a single request +- Updating "out of date" data in the background +- Knowing when data is "out of date" +- Reflecting updates to data as quickly as possible +- Performance optimizations like pagination and lazy loading data +- Managing memory and garbage collection of server state +- Memoizing query results with structural sharing -```tsx -import { - QueryClient, - QueryClientProvider, - createQuery, -} from '@tanstack/solid-query' -import { Match, Switch } from 'solid-js' +This is where **Solid Query** comes in. The library wraps around `createResource` and provides a set of hooks and utilities to manage server state effectively. It works amazingly well **out-of-the-box, with zero-config, and can be customized** to your liking as your application grows. -const queryClient = new QueryClient() +On a more technical note, Solid Query will likely: -export default function App() { - return ( - - - - ) -} +- Help you remove **many** lines of complicated and misunderstood code from your application and replace with just a handful of lines of Solid Query logic. +- Make your application more maintainable and easier to build new features without worrying about wiring up new server state data sources +- Have a direct impact on your end-users by making your application feel faster and more responsive than ever before. +- Potentially help you save on bandwidth and increase memory performance -function Example() { - // ❌ react version -- supports destructing outside reactive context - // const { isPending, error, data } = useQuery({ - // queryKey: ['repoData'], - // queryFn: () => - // fetch('https://api.github.com/repos/tannerlinsley/react-query').then( - // (res) => res.json() - // ), - // }) - - // ✅ solid version -- does not support destructuring outside reactive context - const query = createQuery(() => ({ - queryKey: ['repoData'], - queryFn: () => - fetch('https://api.github.com/repos/tannerlinsley/react-query').then( - (res) => res.json(), - ), - })) +## Enough talk, show me some code already! - // ✅ access query properties in JSX reactive context - return ( - - Loading... - Error: {query.error.message} - -
-

{query.data.name}

-

{query.data.description}

- 👀 {query.data.subscribers_count}{' '} - ✨ {query.data.stargazers_count}{' '} - 🍴 {query.data.forks_count} -
-
-
- ) -} -``` - -- Signals and store values can be passed in directly to function arguments. Solid Query will update the query `store` automatically. +In the example below, you can see Solid Query in its most basic and simple form being used to fetch the GitHub stats for the TanStack Query GitHub project itself: ```tsx +import { ErrorBoundary, Suspense } from 'solid-js' import { + createQuery, QueryClient, QueryClientProvider, - createQuery, } from '@tanstack/solid-query' -import { createSignal, For } from 'solid-js' - -const queryClient = new QueryClient() - -function Example() { - const [enabled, setEnabled] = createSignal(false) - const [todo, setTodo] = createSignal(0) - - // ✅ passing a signal directly is safe and observers update - // automatically when the value of a signal changes - const todosQuery = createQuery(() => ({ - queryKey: ['todos'], - queryFn: fetchTodos, - enabled: enabled(), - })) - const todoDetailsQuery = createQuery(() => ({ - queryKey: ['todo', todo()], - queryFn: fetchTodo, - enabled: todo() > 0, +function App() { + const repositoryQuery = createQuery(() => ({ + queryKey: ['TanStack Query'], + queryFn: async () => { + const result = await fetch('https://api.github.com/repos/TanStack/query') + if (!result.ok) throw new Error('Failed to fetch data') + return result.json() + }, + staleTime: 1000 * 60 * 5, // 5 minutes + throwOnError: true, // Throw an error if the query fails })) return (
- - -

Loading...

-
- -

Error: {query.error.message}

-
- - - {(todo) => ( - - )} - - -
- +
Static Content
+ {/* An error while fetching will be caught by the ErrorBoundary */} + Something went wrong!
}> + {/* Suspense will trigger a loading state while the data is being fetched */} + Loading...}> + {/* + The `data` property on a query is a SolidJS resource + so it will work with Suspense and transitions out of the box! + */} +
{repositoryQuery.data.updated_at}
+
+ ) } -function App() { - return ( - - +const root = document.getElementById('root') +const client = new QueryClient() + +render( + () => ( + + - ) -} + ), + root!, +) ``` -- Errors can be caught and reset using SolidJS' native `ErrorBoundary` component. - Set `throwOnError` or the `suspense` option to `true` to make sure errors are thrown to the `ErrorBoundary` - -- Since Property tracking is handled through Solid's fine grained reactivity, options like `notifyOnChangeProps` are not needed +## Well, that seems like more lines of code to do the same thing? + +Yes it is! But, these few lines of code unlock a whole new world of possibilities. In the example above, your query is cached for 5 minutes, meaning that if a new component mounts anywhere in your app that uses the same query within 5 minutes, it will not re-fetch the data but instead use the cached data. This is just one of the many features that Solid Query provides out of the box. Some other features include: + +- **Automatic Refetching**: Queries automatically refetch in the background when they become "stale" (out of date according to the `staleTime` option) +- **Automatic Caching**: Queries are cached by default and shared across your application +- **Request Deduplication**: Multiple components can share the same query and make one request +- **Automatic Garbage Collection**: Queries are garbage collected when they are no longer needed +- **Window Focus Refetching**: Queries automatically refetch when the application comes back into focus +- **Pagination**: Built-in support for pagination +- **Request Cancellation**: Automatically cancels outdated or unwanted requests +- **Polling/Realtime**: It's easy to add polling or realtime updates to your queries with a simple `refetchInterval` option +- **SSR Support**: Solid Query works great with server-side rendering +- **Optimistic Updates**: Easily update your cache with optimistic updates +- **And much more...** diff --git a/docs/framework/solid/quick-start.md b/docs/framework/solid/quick-start.md new file mode 100644 index 0000000000..944258e591 --- /dev/null +++ b/docs/framework/solid/quick-start.md @@ -0,0 +1,231 @@ +--- +id: quick-start +title: Quick Start +--- + +The `@tanstack/solid-query` package provides a 1st-class API for using TanStack Query with SolidJS. + +## Example + +```tsx +import { + QueryClient, + QueryClientProvider, + createQuery, +} from '@tanstack/solid-query' +import { Switch, Match, For } from 'solid-js' + +const queryClient = new QueryClient() + +function Example() { + const query = createQuery(() => ({ + queryKey: ['todos'], + queryFn: fetchTodos, + })) + + return ( +
+ + +

Loading...

+
+ +

Error: {query.error.message}

+
+ + {(todo) =>

{todo.title}

}
+
+
+
+ ) +} + +function App() { + return ( + + + + ) +} +``` + +## Available Functions + +Solid Query offers useful primitives and functions that will make managing server state in SolidJS apps easier. + +- `createQuery` +- `createQueries` +- `createInfiniteQueries` +- `createMutation` +- `useIsFetching` +- `useIsMutating` +- `useQueryClient` +- `QueryClient` +- `QueryClientProvider` + +## Important Differences between Solid Query & React Query + +Solid Query offers an API similar to React Query, but there are some key differences to be mindful of. + +- Arguments to `solid-query` primitives (like `createQuery`, `createMutation`, `useIsFetching`) listed above are functions, so that they can be tracked in a reactive scope. + +```tsx +// ❌ react version +useQuery({ + queryKey: ['todos', todo], + queryFn: fetchTodos, +}) + +// ✅ solid version +createQuery(() => ({ + queryKey: ['todos', todo], + queryFn: fetchTodos, +})) +``` + +- Suspense works for queries out of the box if you access the query data inside a `` boundary. + +```tsx +import { For, Suspense } from 'solid-js' + +function Example() { + const query = createQuery(() => ({ + queryKey: ['todos'], + queryFn: fetchTodos, + })) + return ( +
+ {/* ✅ Will trigger loading fallback, data accessed in a suspense boundary. */} + + {(todo) =>
{todo.title}
}
+
+ {/* ❌ Will not trigger loading fallback, data not accessed in a suspense boundary. */} + {(todo) =>
{todo.title}
}
+
+ ) +} +``` + +- Solid Query primitives (`createX`) do not support destructuring. The return value from these functions is a store, and their properties are only tracked in a reactive context. + +```tsx +import { + QueryClient, + QueryClientProvider, + createQuery, +} from '@tanstack/solid-query' +import { Match, Switch } from 'solid-js' + +const queryClient = new QueryClient() + +export default function App() { + return ( + + + + ) +} + +function Example() { + // ❌ react version -- supports destructing outside reactive context + // const { isPending, error, data } = useQuery({ + // queryKey: ['repoData'], + // queryFn: () => + // fetch('https://api.github.com/repos/tannerlinsley/react-query').then( + // (res) => res.json() + // ), + // }) + + // ✅ solid version -- does not support destructuring outside reactive context + const query = createQuery(() => ({ + queryKey: ['repoData'], + queryFn: () => + fetch('https://api.github.com/repos/tannerlinsley/react-query').then( + (res) => res.json(), + ), + })) + + // ✅ access query properties in JSX reactive context + return ( + + Loading... + Error: {query.error.message} + +
+

{query.data.name}

+

{query.data.description}

+ 👀 {query.data.subscribers_count}{' '} + ✨ {query.data.stargazers_count}{' '} + 🍴 {query.data.forks_count} +
+
+
+ ) +} +``` + +- Signals and store values can be passed in directly to function arguments. Solid Query will update the query `store` automatically. + +```tsx +import { + QueryClient, + QueryClientProvider, + createQuery, +} from '@tanstack/solid-query' +import { createSignal, For } from 'solid-js' + +const queryClient = new QueryClient() + +function Example() { + const [enabled, setEnabled] = createSignal(false) + const [todo, setTodo] = createSignal(0) + + // ✅ passing a signal directly is safe and observers update + // automatically when the value of a signal changes + const todosQuery = createQuery(() => ({ + queryKey: ['todos'], + queryFn: fetchTodos, + enabled: enabled(), + })) + + const todoDetailsQuery = createQuery(() => ({ + queryKey: ['todo', todo()], + queryFn: fetchTodo, + enabled: todo() > 0, + })) + + return ( +
+ + +

Loading...

+
+ +

Error: {query.error.message}

+
+ + + {(todo) => ( + + )} + + +
+ +
+ ) +} + +function App() { + return ( + + + + ) +} +``` + +- Errors can be caught and reset using SolidJS' native `ErrorBoundary` component. + Set `throwOnError` or the `suspense` option to `true` to make sure errors are thrown to the `ErrorBoundary` + +- Since Property tracking is handled through Solid's fine grained reactivity, options like `notifyOnChangeProps` are not needed diff --git a/docs/framework/solid/typescript.md b/docs/framework/solid/typescript.md new file mode 100644 index 0000000000..aaa2ce7664 --- /dev/null +++ b/docs/framework/solid/typescript.md @@ -0,0 +1,217 @@ +--- +id: typescript +title: TypeScript +--- + +Solid Query is written in **TypeScript** to make sure the library and your projects are type-safe! + +Things to keep in mind: + +- Types currently require using TypeScript **v4.7** or greater +- Changes to types in this repository are considered **non-breaking** and are usually released as **patch** semver changes (otherwise every type enhancement would be a major version!). +- It is **highly recommended that you lock your solid-query package version to a specific patch release and upgrade with the expectation that types may be fixed or upgraded between any release** +- The non-type-related public API of Solid Query still follows semver very strictly. + +## Type Inference + +Types in Solid Query generally flow through very well so that you don't have to provide type annotations for yourself + +```tsx +import { createQuery } from '@tanstack/solid-query' + +const query = createQuery(() => ({ + queryKey: ['number'], + queryFn: () => Promise.resolve(5), +})) + +query.data +// ^? (property) data: number | undefined +``` + +[typescript playground](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAbzgYygUwIYzQRQK5pQCecAvnAGZQQhwDkAAjBgHYDOzyA1gPRsQAbYABMAtAEcCxOgFgAUPOQR28SYRIBeFOiy4pRABQGAlHA0A+OAYTy4duGuIBpNEQBccANp0WeEACNCOgBdABo4W3tHIgAxFg8TM0sABWoQYDY0ADp0fgEANzQDAFZjeVJjMoU5aKzhLAx5Hh57OAA9AH55brkgA) + +```tsx +import { createQuery } from '@tanstack/solid-query' + +const query = createQuery(() => ({ + queryKey: ['test'], + queryFn: () => Promise.resolve(5), + select: (data) => data.toString(), +})) + +query.data +// ^? (property) data: string | undefined +``` + +[typescript playground](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAbzgYygUwIYzQRQK5pQCecAvnAGZQQhwDkAAjBgHYDOzyA1gPRsQAbYABMAtAEcCxOgFgAUPOQR28SYRIBeFOiy4pRABQGAlHA0A+OAYTy4duGuIBpNEQBccANp1sHOgF0AGjhbe0ciADEWDxMzSwAFahBgNjQAOnR+AQA3NAMAVmNA0LtUgTRkGBjhLAxTCzga5jSYCABlGChgFgBzE2K5UmNjeXlwtKaMeR4eezgAPQB+UYU5IA) + +This works best if your `queryFn` has a well-defined returned type. Keep in mind that most data fetching libraries return `any` per default, so make sure to extract it to a properly typed function: + +```tsx +const fetchGroups = (): Promise => + axios.get('/groups').then((response) => response.data) + +const query = createQuery(() => ({ + queryKey: ['groups'], + queryFn: fetchGroups, +})) + +query.data +// ^? (property) data: Group[] | undefined +``` + +[typescript playground](https://www.typescriptlang.org/play/?ssl=11&ssc=4&pln=6&pc=1#code/JYWwDg9gTgLgBAbzgYygUwIYzQRQK5pQCecAvnAGZQQhwDkAAjBgHYDOzyA1gPRsQAbYABMAtAEcCxOgFgAUKEiw4GAB7AIbStVp01GtrLnyYRMGjgBxanjBwAvIjgiAXHBZ4QAI0Jl585Ah2eAo0GGQAC2sIWy1HAAoASjcABR1gNjQAHmjbAG0AXQA+BxL9TQA6AHMw+LoeKpswQ0SKmAi0Fnj0Nkh2C3sSnr7MiuEsDET-OUDguElCEkdUTGx8Rfik0rh4hHk4A-mpIgBpNCI3PLpGmOa6AoAaOH3DheIAMRY3UPCoprYHvJSIkpsY5G8iGMJvIeDxDnAAHoAfmm8iAA) + +## Type Narrowing + +Solid Query uses a [discriminated union type](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions) for the query result, discriminated by the `status` field and the derived status boolean flags. This will allow you to check for e.g. `success` status to make `data` defined: + +```tsx +const query = createQuery(() => ({ + queryKey: ['number'], + queryFn: () => Promise.resolve(5), +})) + +if (query.isSuccess) { + const data = query.data + // ^? const data: number +} +``` + +[typescript playground](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAbzgYygUwIYzQRQK5pQCecAvnAGZQQhwDkAAjBgHYDOzyA1gPRsQAbYABMAtAEcCxOgFgAUKEixEKdFjQBRChTTJ45KjXr8hYgFZtZc+cgjt4kwiQC8qzNnxOAFF4CUcZwA+OC8EeTg4R2IAaTQiAC44AG06FjwQACNCOgBdABpwyKkiADEWRL8A4IAFahBgNjQAOnQTADc0LwBWXwK5Ul9feXlgChCooiaGgGU8ZGQ0NjZ-MLkIiNt7OGEsDACipyad5kKInh51iIA9AH55UmHrOSA) + +## Typing the error field + +The type for error defaults to `Error`, because that is what most users expect. + +```tsx +const query = createQuery(() => ({ + queryKey: ['groups'], + queryFn: fetchGroups, +})) + +query.error +// ^? (property) error: Error | null +``` + +[typescript playground](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAbzgYygUwIYzQRQK5pQCecAvnAGZQQhwDkAAjBgHYDOzyA1gPRsQAbYABMAtAEcCxOgFgAUKEiw4GAB7AIbStVp01GtrLnyYRMGjgBxanjBwAvIjgiAXHBZ4QAI0Jl585Ah2eAo0GGQAC2sIWy1HAAoASjcABR1gNjQAHmjbAG0AXQA+BxL9TQA6AHMw+LoeKpswQ0SKmAi0Fnj0Nkh2C3sSnr7MiuEsDET-OUDguElCEkdUTGx8Rfik0rh4hHk4A-mpIgBpNCI3PLpGmOa6AoAaOH3DheIAMRY3UPCoprYHvJSIkpsY5G8iBVCNQoPIeDxDnAAHoAfmm8iAA) + +If you want to throw a custom error, or something that isn't an `Error` at all, you can specify the type of the error field: + +```tsx +const query = createQuery(() => ({ + queryKey: ['groups'], + queryFn: fetchGroups, +})) + +query.error +// ^? (property) error: string | null +``` + +However, this has the drawback that type inference for all other generics of `useQuery` will not work anymore. It is generally not considered a good practice to throw something that isn't an `Error`, so if you have a subclass like `AxiosError` you can use _type narrowing_ to make the error field more specific: + +```tsx +import axios from 'axios' + +const query = createQuery(() => ({ + queryKey: ['groups'], + queryFn: fetchGroups, +})) + +query.error +// ^? (property) error: Error | null + +if (axios.isAxiosError(query.error)) { + query.error + // ^? (property) error: AxiosError +} +``` + +[typescript playground](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAbzgYygUwIYzQRQK5pQCecAvnAGZQQhwDkAAjBgHYDOzyA1gPRsQAbYABMAtAEcCxOgFgAUKEiw4GAB7AIbStVp01GtrLnyYRMGjgBxanjBwAvIjgiAXHBZ4QAI0Jl585Ah2eAo0GGQAC2sIWy1HAAoASjcABR1gNjQAHmjbAG0AXQA+BxL9TQA6AHMw+LoeKpswQ0SKmAi0Fnj0Nkh2C3sSnr7MiuEsDET-OUDguElCEkdUTGx8Rfik0rh4hHk4A-mpIgBpNCI3PLpGmOa6AoAaOH3DheIAMRY3UPCoprYHvJSIkpsY5G8iBVCNQoPIeDxDnAAHoAfmmwAoO3KbAqGQAgupNABRKAw+IQqGk6AgxAvA4U6HQOlweGI1FA+RAA) + +## Registering a global `Error` + +TanStack Query v5 allows for a way to set a global Error type for everything, without having to specify generics on call-sides, by amending the `Register` interface. This will make sure inference still works, but the error field will be of the specified type: + +```tsx +import '@tanstack/solid-query' + +declare module '@tanstack/solid-query' { + interface Register { + defaultError: AxiosError + } +} + +const query = createQuery(() => ({ + queryKey: ['groups'], + queryFn: fetchGroups, +})) + +query.error +// ^? (property) error: AxiosError | null +``` + +## Registering global `Meta` + +Similarly to registering a [global error type](#registering-a-global-error) you can also register a global `Meta` type. This ensures the optional `meta` field on [queries](../createQuery) and [mutations](../createMutation) stays consistent and is type-safe. Note that the registered type must extend `Record` so that `meta` remains an object. + +```ts +import '@tanstack/solid-query' + +interface MyMeta extends Record { + // Your meta type definition. +} + +declare module '@tanstack/solid-query' { + interface Register { + queryMeta: MyMeta + mutationMeta: MyMeta + } +} +``` + +## Typing Query Options + +If you inline query options into `createQuery`, you'll get automatic type inference. However, you might want to extract the query options into a separate function to share them between `createQuery` and e.g. `prefetchQuery`. In that case, you'd lose type inference. To get it back, you can use `queryOptions` helper: + +```ts +import { queryOptions } from '@tanstack/solid-query' + +function groupOptions() { + return queryOptions({ + queryKey: ['groups'], + queryFn: fetchGroups, + staleTime: 5 * 1000, + }) +} + +createQuery(groupOptions) +queryClient.prefetchQuery(groupOptions()) +``` + +Further, the `queryKey` returned from `queryOptions` knows about the `queryFn` associated with it, and we can leverage that type information to make functions like `queryClient.getQueryData` aware of those types as well: + +```ts +function groupOptions() { + return queryOptions({ + queryKey: ['groups'], + queryFn: fetchGroups, + staleTime: 5 * 1000, + }) +} + +const data = queryClient.getQueryData(groupOptions().queryKey) +// ^? const data: Group[] | undefined +``` + +Without `queryOptions`, the type of `data` would be `unknown`, unless we'd pass a generic to it: + +```ts +const data = queryClient.getQueryData(['groups']) +``` + +## Typesafe disabling of queries using `skipToken` + +If you are using TypeScript, you can use the `skipToken` to disable a query. This is useful when you want to disable a query based on a condition, but you still want to keep the query to be type safe. + +Read more about it in the [Disabling Queries](../disabling-queries) guide.