From df77d8cd8bbee4d933797e00eb0cee452c25d1f9 Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Wed, 15 Apr 2026 16:47:54 +0900 Subject: [PATCH 1/3] test(svelte-query/createMutation): add type tests for generic type inference and callbacks (#10502) --- .../createMutation/createMutation.test-d.ts | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 packages/svelte-query/tests/createMutation/createMutation.test-d.ts diff --git a/packages/svelte-query/tests/createMutation/createMutation.test-d.ts b/packages/svelte-query/tests/createMutation/createMutation.test-d.ts new file mode 100644 index 00000000000..4ea6027949e --- /dev/null +++ b/packages/svelte-query/tests/createMutation/createMutation.test-d.ts @@ -0,0 +1,138 @@ +import { describe, expectTypeOf, it } from 'vitest' +import { QueryClient } from '@tanstack/query-core' +import { createMutation } from '../../src/index.js' +import type { DefaultError } from '@tanstack/query-core' +import type { CreateMutationResult } from '../../src/types.js' + +describe('createMutation', () => { + it('should infer TData from mutationFn return type', () => { + const mutation = createMutation(() => ({ + mutationFn: () => Promise.resolve('data'), + })) + + expectTypeOf(mutation.data).toEqualTypeOf() + expectTypeOf(mutation.error).toEqualTypeOf() + }) + + it('should infer TVariables from mutationFn parameter', () => { + const mutation = createMutation(() => ({ + mutationFn: (vars: { id: string }) => Promise.resolve(vars.id), + })) + + expectTypeOf(mutation.mutate).toBeCallableWith({ id: '1' }) + expectTypeOf(mutation.data).toEqualTypeOf() + }) + + it('should infer TOnMutateResult from onMutate return type', () => { + createMutation(() => ({ + mutationFn: () => Promise.resolve('data'), + onMutate: () => { + return { token: 'abc' } + }, + onSuccess: (_data, _variables, onMutateResult) => { + expectTypeOf(onMutateResult).toEqualTypeOf<{ token: string }>() + }, + onError: (_error, _variables, onMutateResult) => { + expectTypeOf(onMutateResult).toEqualTypeOf< + { token: string } | undefined + >() + }, + })) + }) + + it('should allow explicit generic types', () => { + const mutation = createMutation(() => ({ + mutationFn: (vars) => { + expectTypeOf(vars).toEqualTypeOf<{ id: number }>() + return Promise.resolve('result') + }, + })) + + expectTypeOf(mutation.data).toEqualTypeOf() + expectTypeOf(mutation.error).toEqualTypeOf() + }) + + it('should return correct CreateMutationResult type', () => { + const mutation = createMutation(() => ({ + mutationFn: () => Promise.resolve(42), + })) + + expectTypeOf(mutation).toEqualTypeOf< + CreateMutationResult + >() + }) + + it('should type mutateAsync with correct return type', () => { + const mutation = createMutation(() => ({ + mutationFn: (id: string) => Promise.resolve(id.length), + })) + + expectTypeOf(mutation.mutateAsync).toBeCallableWith('test') + expectTypeOf(mutation.mutateAsync('test')).toEqualTypeOf>() + }) + + it('should default TVariables to void when mutationFn has no parameters', () => { + const mutation = createMutation(() => ({ + mutationFn: () => Promise.resolve('data'), + })) + + expectTypeOf(mutation.mutate).toBeCallableWith() + }) + + it('should infer custom TError type', () => { + class CustomError extends Error { + code: number + constructor(code: number) { + super() + this.code = code + } + } + + const mutation = createMutation(() => ({ + mutationFn: () => Promise.resolve('data'), + })) + + expectTypeOf(mutation.error).toEqualTypeOf() + expectTypeOf(mutation.data).toEqualTypeOf() + }) + + it('should infer types for onSettled callback', () => { + createMutation(() => ({ + mutationFn: () => Promise.resolve(42), + onSettled: (data, error, _variables, _onMutateResult) => { + expectTypeOf(data).toEqualTypeOf() + expectTypeOf(error).toEqualTypeOf() + }, + })) + }) + + it('should infer custom TError in onError callback', () => { + class CustomError extends Error { + code: number + constructor(code: number) { + super() + this.code = code + } + } + + createMutation(() => ({ + mutationFn: () => Promise.resolve('data'), + onError: (error) => { + expectTypeOf(error).toEqualTypeOf() + }, + })) + }) + + it('should accept queryClient as second argument', () => { + const queryClient = new QueryClient() + + const mutation = createMutation( + () => ({ + mutationFn: () => Promise.resolve('data'), + }), + () => queryClient, + ) + + expectTypeOf(mutation.data).toEqualTypeOf() + }) +}) From da62c8a4040c31a720b5e774615ec7a5b186dcff Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Wed, 15 Apr 2026 17:03:11 +0900 Subject: [PATCH 2/3] test(svelte-query/createInfiniteQuery): add type tests for page params, 'initialData', 'select', and 'Accessor' (#10503) --- .../createInfiniteQuery.test-d.ts | 209 ++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 packages/svelte-query/tests/createInfiniteQuery/createInfiniteQuery.test-d.ts diff --git a/packages/svelte-query/tests/createInfiniteQuery/createInfiniteQuery.test-d.ts b/packages/svelte-query/tests/createInfiniteQuery/createInfiniteQuery.test-d.ts new file mode 100644 index 00000000000..1214e8f52ce --- /dev/null +++ b/packages/svelte-query/tests/createInfiniteQuery/createInfiniteQuery.test-d.ts @@ -0,0 +1,209 @@ +import { describe, expectTypeOf, it } from 'vitest' +import { QueryClient } from '@tanstack/query-core' +import { queryKey } from '@tanstack/query-test-utils' +import { createInfiniteQuery } from '../../src/index.js' +import type { InfiniteData } from '@tanstack/query-core' + +describe('createInfiniteQuery', () => { + describe('pageParam', () => { + it('initialPageParam should define type of param passed to queryFunctionContext', () => { + createInfiniteQuery(() => ({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + expectTypeOf(pageParam).toEqualTypeOf() + }, + initialPageParam: 1, + getNextPageParam: () => undefined, + })) + }) + + it('direction should be passed to queryFn of createInfiniteQuery', () => { + createInfiniteQuery(() => ({ + queryKey: queryKey(), + queryFn: ({ direction }) => { + expectTypeOf(direction).toEqualTypeOf<'forward' | 'backward'>() + }, + initialPageParam: 1, + getNextPageParam: () => undefined, + })) + }) + + it('initialPageParam should define type of param passed to queryFunctionContext for fetchInfiniteQuery', () => { + const queryClient = new QueryClient() + queryClient.fetchInfiniteQuery({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + expectTypeOf(pageParam).toEqualTypeOf() + }, + initialPageParam: 1, + }) + }) + + it('initialPageParam should define type of param passed to queryFunctionContext for prefetchInfiniteQuery', () => { + const queryClient = new QueryClient() + queryClient.prefetchInfiniteQuery({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + expectTypeOf(pageParam).toEqualTypeOf() + }, + initialPageParam: 1, + }) + }) + }) + + describe('initialData', () => { + it('TData should have undefined in the union even when initialData is provided', () => { + const { data } = createInfiniteQuery(() => ({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + return pageParam * 5 + }, + initialPageParam: 1, + getNextPageParam: () => undefined, + initialData: { pages: [5], pageParams: [1] }, + })) + + // TODO: Order of generics prevents pageParams to be typed correctly. Using `unknown` for now + expectTypeOf(data).toEqualTypeOf< + InfiniteData | undefined + >() + }) + + it('TData should have undefined in the union when initialData is NOT provided', () => { + const { data } = createInfiniteQuery(() => ({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + return pageParam * 5 + }, + initialPageParam: 1, + getNextPageParam: () => undefined, + })) + + expectTypeOf(data).toEqualTypeOf< + InfiniteData | undefined + >() + }) + }) + + describe('select', () => { + it('should still return paginated data if no select result', () => { + const infiniteQuery = createInfiniteQuery(() => ({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + return pageParam * 5 + }, + initialPageParam: 1, + getNextPageParam: () => undefined, + })) + + // TODO: Order of generics prevents pageParams to be typed correctly. Using `unknown` for now + expectTypeOf(infiniteQuery.data).toEqualTypeOf< + InfiniteData | undefined + >() + }) + + it('should be able to transform data to arbitrary result', () => { + const infiniteQuery = createInfiniteQuery(() => ({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + return pageParam * 5 + }, + initialPageParam: 1, + getNextPageParam: () => undefined, + select: (data) => { + expectTypeOf(data).toEqualTypeOf>() + return 'selected' as const + }, + })) + + expectTypeOf(infiniteQuery.data).toEqualTypeOf<'selected' | undefined>() + }) + }) + + describe('getNextPageParam / getPreviousPageParam', () => { + it('should get typed params', () => { + const infiniteQuery = createInfiniteQuery(() => ({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + return String(pageParam) + }, + initialPageParam: 1, + getNextPageParam: ( + lastPage, + allPages, + lastPageParam, + allPageParams, + ) => { + expectTypeOf(lastPage).toEqualTypeOf() + expectTypeOf(allPages).toEqualTypeOf>() + expectTypeOf(lastPageParam).toEqualTypeOf() + expectTypeOf(allPageParams).toEqualTypeOf>() + return undefined + }, + getPreviousPageParam: ( + firstPage, + allPages, + firstPageParam, + allPageParams, + ) => { + expectTypeOf(firstPage).toEqualTypeOf() + expectTypeOf(allPages).toEqualTypeOf>() + expectTypeOf(firstPageParam).toEqualTypeOf() + expectTypeOf(allPageParams).toEqualTypeOf>() + return undefined + }, + })) + + // TODO: Order of generics prevents pageParams to be typed correctly. Using `unknown` for now + expectTypeOf(infiniteQuery.data).toEqualTypeOf< + InfiniteData | undefined + >() + }) + }) + + describe('error booleans', () => { + it('should not be permanently `false`', () => { + const { + isFetchNextPageError, + isFetchPreviousPageError, + isLoadingError, + isRefetchError, + } = createInfiniteQuery(() => ({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + return pageParam * 5 + }, + initialPageParam: 1, + getNextPageParam: () => undefined, + })) + + expectTypeOf(isFetchNextPageError).toEqualTypeOf() + expectTypeOf(isFetchPreviousPageError).toEqualTypeOf() + expectTypeOf(isLoadingError).toEqualTypeOf() + expectTypeOf(isRefetchError).toEqualTypeOf() + }) + }) + + describe('queryClient', () => { + it('should accept queryClient as second argument', () => { + const queryClient = new QueryClient() + + const infiniteQuery = createInfiniteQuery( + () => ({ + queryKey: queryKey(), + queryFn: ({ pageParam }) => { + return pageParam * 5 + }, + initialPageParam: 1, + getNextPageParam: () => undefined, + }), + () => queryClient, + ) + + // TODO: Order of generics prevents pageParams to be typed correctly. Using `unknown` for now + expectTypeOf(infiniteQuery.data).toEqualTypeOf< + InfiniteData | undefined + >() + }) + }) +}) From c47c67132df06dbc13244936862339aa845caebb Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Wed, 15 Apr 2026 17:39:31 +0900 Subject: [PATCH 3/3] test(svelte-query/useMutationState): add type tests for default 'MutationState' and 'select' inference (#10504) --- .../useMutationState.test-d.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/svelte-query/tests/useMutationState/useMutationState.test-d.ts diff --git a/packages/svelte-query/tests/useMutationState/useMutationState.test-d.ts b/packages/svelte-query/tests/useMutationState/useMutationState.test-d.ts new file mode 100644 index 00000000000..1863f0a4233 --- /dev/null +++ b/packages/svelte-query/tests/useMutationState/useMutationState.test-d.ts @@ -0,0 +1,24 @@ +import { describe, expectTypeOf, it } from 'vitest' +import { useMutationState } from '../../src/index.js' +import type { MutationState, MutationStatus } from '@tanstack/query-core' + +describe('useMutationState', () => { + it('should default to MutationState', () => { + const result = useMutationState({ + filters: { status: 'pending' }, + }) + + expectTypeOf(result).toEqualTypeOf< + Array> + >() + }) + + it('should infer with select', () => { + const result = useMutationState({ + filters: { status: 'pending' }, + select: (mutation) => mutation.state.status, + }) + + expectTypeOf(result).toEqualTypeOf>() + }) +})