Skip to content

Commit c280468

Browse files
committed
fix(tanstack): improve typing of mutation errors
1 parent 32f677c commit c280468

File tree

9 files changed

+69
-26
lines changed

9 files changed

+69
-26
lines changed

packages/plugins/tanstack-query/src/generator.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ function generateMutationHook(
216216
{
217217
name: `_mutation`,
218218
initializer: `
219-
useModelMutation<${argsType}, ${
219+
useModelMutation<${argsType}, DefaultError, ${
220220
overrideReturnType ?? model
221221
}, ${checkReadBack}>('${model}', '${httpVerb.toUpperCase()}', \`\${endpoint}/${lowerCaseFirst(
222222
model
@@ -565,9 +565,9 @@ function makeBaseImports(target: TargetFramework, version: TanStackVersion) {
565565
const runtimeImportBase = makeRuntimeImportBase(version);
566566
const shared = [
567567
`import { useModelQuery, useInfiniteModelQuery, useModelMutation } from '${runtimeImportBase}/${target}';`,
568-
`import type { PickEnumerable, CheckSelect } from '${runtimeImportBase}';`,
568+
`import type { PickEnumerable, CheckSelect, QueryError } from '${runtimeImportBase}';`,
569569
`import metadata from './__model_meta';`,
570-
`type DefaultError = Error;`,
570+
`type DefaultError = QueryError;`,
571571
];
572572
switch (target) {
573573
case 'react': {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from '../runtime/prisma-types';
2-
export { type FetchFn, getQueryKey } from '../runtime/common';
2+
export { type FetchFn, type QueryError, getQueryKey } from '../runtime/common';

packages/plugins/tanstack-query/src/runtime-v5/react.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22
import {
3+
UseSuspenseInfiniteQueryOptions,
4+
UseSuspenseQueryOptions,
35
useInfiniteQuery,
46
useMutation,
57
useQuery,
@@ -10,21 +12,19 @@ import {
1012
type UseInfiniteQueryOptions,
1113
type UseMutationOptions,
1214
type UseQueryOptions,
13-
UseSuspenseInfiniteQueryOptions,
14-
UseSuspenseQueryOptions,
1515
} from '@tanstack/react-query-v5';
1616
import type { ModelMeta } from '@zenstackhq/runtime/cross';
1717
import { createContext, useContext } from 'react';
1818
import {
1919
DEFAULT_QUERY_ENDPOINT,
20-
FetchFn,
2120
fetcher,
2221
getQueryKey,
2322
makeUrl,
2423
marshal,
2524
setupInvalidation,
2625
setupOptimisticUpdate,
2726
type APIContext,
27+
type FetchFn,
2828
} from '../runtime/common';
2929

3030
/**
@@ -167,12 +167,18 @@ export function useSuspenseInfiniteModelQuery<TQueryFnData, TData, TError>(
167167
* @param checkReadBack Whether to check for read back errors and return undefined if found.
168168
* @param optimisticUpdate Whether to enable automatic optimistic update
169169
*/
170-
export function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(
170+
export function useModelMutation<
171+
TArgs,
172+
TError,
173+
R = any,
174+
C extends boolean = boolean,
175+
Result = C extends true ? R | undefined : R
176+
>(
171177
model: string,
172178
method: 'POST' | 'PUT' | 'DELETE',
173179
url: string,
174180
modelMeta: ModelMeta,
175-
options?: Omit<UseMutationOptions<Result, unknown, T>, 'mutationFn'>,
181+
options?: Omit<UseMutationOptions<Result, TError, TArgs>, 'mutationFn'>,
176182
fetch?: FetchFn,
177183
invalidateQueries = true,
178184
checkReadBack?: C,

packages/plugins/tanstack-query/src/runtime-v5/svelte.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ import { Readable, derived } from 'svelte/store';
1616
import {
1717
APIContext,
1818
DEFAULT_QUERY_ENDPOINT,
19-
FetchFn,
2019
fetcher,
2120
getQueryKey,
2221
makeUrl,
2322
marshal,
2423
setupInvalidation,
2524
setupOptimisticUpdate,
25+
type FetchFn,
2626
} from '../runtime/common';
2727

2828
export { APIContext as RequestHandlerContext } from '../runtime/common';
@@ -147,12 +147,18 @@ function isStore<T>(opt: unknown): opt is Readable<T> {
147147
* @param invalidateQueries Whether to invalidate queries after mutation.
148148
* @returns useMutation hooks
149149
*/
150-
export function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(
150+
export function useModelMutation<
151+
TArgs,
152+
TError,
153+
R = any,
154+
C extends boolean = boolean,
155+
Result = C extends true ? R | undefined : R
156+
>(
151157
model: string,
152158
method: 'POST' | 'PUT' | 'DELETE',
153159
url: string,
154160
modelMeta: ModelMeta,
155-
options?: Omit<MutationOptions<Result, unknown, T>, 'mutationFn'>,
161+
options?: Omit<MutationOptions<Result, TError, TArgs>, 'mutationFn'>,
156162
fetch?: FetchFn,
157163
invalidateQueries = true,
158164
checkReadBack?: C,

packages/plugins/tanstack-query/src/runtime/common.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ export const QUERY_KEY_PREFIX = 'zenstack';
2525
*/
2626
export type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;
2727

28+
/**
29+
* Type for query and mutation errors.
30+
*/
31+
export type QueryError = Error & {
32+
/**
33+
* Additional error information.
34+
*/
35+
info?: unknown;
36+
37+
/**
38+
* HTTP status code.
39+
*/
40+
status?: number;
41+
};
42+
2843
/**
2944
* Context type for configuring the hooks.
3045
*/
@@ -64,9 +79,7 @@ export async function fetcher<R, C extends boolean>(
6479
// policy doesn't allow mutation result to be read back, just return undefined
6580
return undefined as any;
6681
}
67-
const error: Error & { info?: unknown; status?: number } = new Error(
68-
'An error occurred while fetching the data.'
69-
);
82+
const error: QueryError = new Error('An error occurred while fetching the data.');
7083
error.info = errData.error;
7184
error.status = res.status;
7285
throw error;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from './prisma-types';
2-
export { type FetchFn, getQueryKey } from './common';
2+
export { type FetchFn, type QueryError, getQueryKey } from './common';

packages/plugins/tanstack-query/src/runtime/react.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ import type { ModelMeta } from '@zenstackhq/runtime/cross';
1212
import { createContext, useContext } from 'react';
1313
import {
1414
DEFAULT_QUERY_ENDPOINT,
15-
FetchFn,
1615
fetcher,
1716
getQueryKey,
1817
makeUrl,
1918
marshal,
2019
setupInvalidation,
2120
setupOptimisticUpdate,
2221
type APIContext,
22+
type FetchFn,
2323
} from './common';
2424

2525
/**
@@ -110,12 +110,18 @@ export function useInfiniteModelQuery<TQueryFnData, TData, TError>(
110110
* @param optimisticUpdate Whether to enable automatic optimistic update
111111
* @returns useMutation hooks
112112
*/
113-
export function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(
113+
export function useModelMutation<
114+
TArgs,
115+
TError,
116+
R = any,
117+
C extends boolean = boolean,
118+
Result = C extends true ? R | undefined : R
119+
>(
114120
model: string,
115121
method: 'POST' | 'PUT' | 'DELETE',
116122
url: string,
117123
modelMeta: ModelMeta,
118-
options?: Omit<UseMutationOptions<Result, unknown, T>, 'mutationFn'>,
124+
options?: Omit<UseMutationOptions<Result, TError, TArgs>, 'mutationFn'>,
119125
fetch?: FetchFn,
120126
invalidateQueries = true,
121127
checkReadBack?: C,

packages/plugins/tanstack-query/src/runtime/svelte.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import { getContext, setContext } from 'svelte';
1313
import {
1414
APIContext,
1515
DEFAULT_QUERY_ENDPOINT,
16-
FetchFn,
1716
fetcher,
1817
getQueryKey,
1918
makeUrl,
2019
marshal,
2120
setupInvalidation,
2221
setupOptimisticUpdate,
22+
type FetchFn,
2323
} from './common';
2424

2525
export { APIContext as RequestHandlerContext } from './common';
@@ -109,12 +109,18 @@ export function useInfiniteModelQuery<TQueryFnData, TData, TError>(
109109
* @param optimisticUpdate Whether to enable automatic optimistic update.
110110
* @returns useMutation hooks
111111
*/
112-
export function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(
112+
export function useModelMutation<
113+
TArgs,
114+
TError,
115+
R = any,
116+
C extends boolean = boolean,
117+
Result = C extends true ? R | undefined : R
118+
>(
113119
model: string,
114120
method: 'POST' | 'PUT' | 'DELETE',
115121
url: string,
116122
modelMeta: ModelMeta,
117-
options?: Omit<MutationOptions<Result, unknown, T>, 'mutationFn'>,
123+
options?: Omit<MutationOptions<Result, TError, TArgs>, 'mutationFn'>,
118124
fetch?: FetchFn,
119125
invalidateQueries = true,
120126
checkReadBack?: C,

packages/plugins/tanstack-query/src/runtime/vue.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ import { inject, provide } from 'vue';
1414
import {
1515
APIContext,
1616
DEFAULT_QUERY_ENDPOINT,
17-
FetchFn,
1817
fetcher,
1918
getQueryKey,
2019
makeUrl,
2120
marshal,
2221
setupInvalidation,
2322
setupOptimisticUpdate,
23+
type FetchFn,
2424
} from './common';
2525

2626
export { APIContext as RequestHandlerContext } from './common';
@@ -113,12 +113,18 @@ export function useInfiniteModelQuery<TQueryFnData, TData, TError>(
113113
* @param optimisticUpdate Whether to enable automatic optimistic update
114114
* @returns useMutation hooks
115115
*/
116-
export function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(
116+
export function useModelMutation<
117+
TArgs,
118+
TError,
119+
R = any,
120+
C extends boolean = boolean,
121+
Result = C extends true ? R | undefined : R
122+
>(
117123
model: string,
118124
method: 'POST' | 'PUT' | 'DELETE',
119125
url: string,
120126
modelMeta: ModelMeta,
121-
options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>,
127+
options?: Omit<UseMutationOptions<Result, TError, TArgs, unknown>, 'mutationFn'>,
122128
fetch?: FetchFn,
123129
invalidateQueries = true,
124130
checkReadBack?: C,
@@ -168,5 +174,5 @@ export function useModelMutation<T, R = any, C extends boolean = boolean, Result
168174
);
169175
}
170176
}
171-
return useMutation<Result, unknown, T>(finalOptions);
177+
return useMutation(finalOptions);
172178
}

0 commit comments

Comments
 (0)