diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts index b6d611b778..d3a8581a8b 100644 --- a/packages/toolkit/src/query/react/buildHooks.ts +++ b/packages/toolkit/src/query/react/buildHooks.ts @@ -98,6 +98,12 @@ export type UseQuery<D extends QueryDefinition<any, any, any, any>> = < options?: UseQuerySubscriptionOptions & UseQueryStateOptions<D, R>, ) => UseQueryHookResult<D, R> +export type TypedUseQuery< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, +> = UseQuery<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>> + export type UseQueryHookResult< D extends QueryDefinition<any, any, any, any>, R = UseQueryStateDefaultResult<D>, @@ -182,6 +188,14 @@ export type UseQuerySubscription< options?: UseQuerySubscriptionOptions, ) => UseQuerySubscriptionResult<D> +export type TypedUseQuerySubscription< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, +> = UseQuerySubscription< + QueryDefinition<QueryArg, BaseQuery, string, ResultType, string> +> + export type UseQuerySubscriptionResult< D extends QueryDefinition<any, any, any, any>, > = Pick<QueryActionCreatorResult<D>, 'refetch'> @@ -231,6 +245,14 @@ export type UseLazyQuery<D extends QueryDefinition<any, any, any, any>> = < UseLazyQueryLastPromiseInfo<D>, ] +export type TypedUseLazyQuery< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, +> = UseLazyQuery< + QueryDefinition<QueryArg, BaseQuery, string, ResultType, string> +> + export type LazyQueryTrigger<D extends QueryDefinition<any, any, any, any>> = { /** * Triggers a lazy query. @@ -258,6 +280,14 @@ export type LazyQueryTrigger<D extends QueryDefinition<any, any, any, any>> = { ): QueryActionCreatorResult<D> } +export type TypedLazyQueryTrigger< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, +> = LazyQueryTrigger< + QueryDefinition<QueryArg, BaseQuery, string, ResultType, string> +> + /** * A React hook similar to [`useQuerySubscription`](#usequerysubscription), but with manual control over when the data fetching occurs. * @@ -275,6 +305,14 @@ export type UseLazyQuerySubscription< options?: SubscriptionOptions, ) => readonly [LazyQueryTrigger<D>, QueryArgFrom<D> | UninitializedValue] +export type TypedUseLazyQuerySubscription< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, +> = UseLazyQuerySubscription< + QueryDefinition<QueryArg, BaseQuery, string, ResultType, string> +> + export type QueryStateSelector< R extends Record<string, any>, D extends QueryDefinition<any, any, any, any>, @@ -297,6 +335,14 @@ export type UseQueryState<D extends QueryDefinition<any, any, any, any>> = < options?: UseQueryStateOptions<D, R>, ) => UseQueryStateResult<D, R> +export type TypedUseQueryState< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, +> = UseQueryState< + QueryDefinition<QueryArg, BaseQuery, string, ResultType, string> +> + export type UseQueryStateOptions< D extends QueryDefinition<any, any, any, any>, R extends Record<string, any>, @@ -514,6 +560,14 @@ export type UseMutation<D extends MutationDefinition<any, any, any, any>> = < options?: UseMutationStateOptions<D, R>, ) => readonly [MutationTrigger<D>, UseMutationStateResult<D, R>] +export type TypedUseMutation< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, +> = UseMutation< + MutationDefinition<QueryArg, BaseQuery, string, ResultType, string> +> + export type MutationTrigger<D extends MutationDefinition<any, any, any, any>> = { /** @@ -535,6 +589,14 @@ export type MutationTrigger<D extends MutationDefinition<any, any, any, any>> = (arg: QueryArgFrom<D>): MutationActionCreatorResult<D> } +export type TypedUseMutationTrigger< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, +> = MutationTrigger< + MutationDefinition<QueryArg, BaseQuery, string, ResultType, string> +> + /** * Wrapper around `defaultQueryStateSelector` to be used in `useQuery`. * We want the initial render to already come back with diff --git a/packages/toolkit/src/query/react/index.ts b/packages/toolkit/src/query/react/index.ts index b9acba6b6b..ba2815f123 100644 --- a/packages/toolkit/src/query/react/index.ts +++ b/packages/toolkit/src/query/react/index.ts @@ -18,5 +18,13 @@ export type { TypedUseQueryHookResult, TypedUseQueryStateResult, TypedUseQuerySubscriptionResult, + TypedLazyQueryTrigger, + TypedUseLazyQuery, + TypedUseMutation, + TypedUseMutationTrigger, + TypedUseQueryState, + TypedUseQuery, + TypedUseQuerySubscription, + TypedUseLazyQuerySubscription, } from './buildHooks' export { createApi, reactHooksModule, reactHooksModuleName } diff --git a/packages/toolkit/src/query/tests/buildHooks.test-d.tsx b/packages/toolkit/src/query/tests/buildHooks.test-d.tsx index 9e15bf68ee..25551c000c 100644 --- a/packages/toolkit/src/query/tests/buildHooks.test-d.tsx +++ b/packages/toolkit/src/query/tests/buildHooks.test-d.tsx @@ -193,7 +193,7 @@ describe('type tests', () => { } }) - test('selectFromResult (query) behaviors', () => { + test('top level named hooks', () => { interface Post { id: number name: string diff --git a/packages/toolkit/src/query/tests/unionTypes.test-d.ts b/packages/toolkit/src/query/tests/unionTypes.test-d.ts index d47cdae41b..2ab109dfa9 100644 --- a/packages/toolkit/src/query/tests/unionTypes.test-d.ts +++ b/packages/toolkit/src/query/tests/unionTypes.test-d.ts @@ -3,8 +3,16 @@ import type { FetchBaseQueryError, TypedUseMutationResult, TypedUseQueryHookResult, + TypedUseQueryState, TypedUseQueryStateResult, TypedUseQuerySubscriptionResult, + TypedLazyQueryTrigger, + TypedUseLazyQuery, + TypedUseLazyQuerySubscription, + TypedUseMutation, + TypedUseMutationTrigger, + TypedUseQuerySubscription, + TypedUseQuery, } from '@reduxjs/toolkit/query/react' import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' @@ -725,6 +733,10 @@ describe('union types', () => { describe('"Typed" helper types', () => { test('useQuery', () => { + expectTypeOf<TypedUseQuery<string, void, typeof baseQuery>>().toMatchTypeOf( + api.endpoints.getTest.useQuery, + ) + const result = api.endpoints.getTest.useQuery() expectTypeOf< @@ -743,6 +755,10 @@ describe('"Typed" helper types', () => { }) test('useQueryState', () => { + expectTypeOf< + TypedUseQueryState<string, void, typeof baseQuery> + >().toMatchTypeOf(api.endpoints.getTest.useQueryState) + const result = api.endpoints.getTest.useQueryState() expectTypeOf< @@ -761,6 +777,10 @@ describe('"Typed" helper types', () => { }) test('useQuerySubscription', () => { + expectTypeOf< + TypedUseQuerySubscription<string, void, typeof baseQuery> + >().toMatchTypeOf(api.endpoints.getTest.useQuerySubscription) + const result = api.endpoints.getTest.useQuerySubscription() expectTypeOf< @@ -768,11 +788,101 @@ describe('"Typed" helper types', () => { >().toEqualTypeOf(result) }) + test('useLazyQuery', () => { + expectTypeOf< + TypedUseLazyQuery<string, void, typeof baseQuery> + >().toMatchTypeOf(api.endpoints.getTest.useLazyQuery) + + const [trigger, result] = api.endpoints.getTest.useLazyQuery() + + expectTypeOf< + TypedLazyQueryTrigger<string, void, typeof baseQuery> + >().toMatchTypeOf(trigger) + + expectTypeOf< + TypedUseQueryHookResult<string, void, typeof baseQuery> + >().toMatchTypeOf(result) + }) + + test('useLazyQuery with selectFromResult', () => { + const [trigger, result] = api.endpoints.getTest.useLazyQuery({ + selectFromResult: () => ({ x: true }), + }) + + expectTypeOf< + TypedLazyQueryTrigger<string, void, typeof baseQuery> + >().toMatchTypeOf(trigger) + + expectTypeOf< + TypedUseQueryHookResult<string, void, typeof baseQuery, { x: boolean }> + >().toMatchTypeOf(result) + }) + + test('useLazyQuerySubscription', () => { + expectTypeOf< + TypedUseLazyQuerySubscription<string, void, typeof baseQuery> + >().toMatchTypeOf(api.endpoints.getTest.useLazyQuerySubscription) + + const [trigger] = api.endpoints.getTest.useLazyQuerySubscription() + + expectTypeOf< + TypedLazyQueryTrigger<string, void, typeof baseQuery> + >().toMatchTypeOf(trigger) + }) + test('useMutation', () => { + expectTypeOf< + TypedUseMutation<string, void, typeof baseQuery> + >().toMatchTypeOf(api.endpoints.mutation.useMutation) + const [trigger, result] = api.endpoints.mutation.useMutation() + expectTypeOf< + TypedUseMutationTrigger<string, void, typeof baseQuery> + >().toMatchTypeOf(trigger) + expectTypeOf< TypedUseMutationResult<string, void, typeof baseQuery> >().toMatchTypeOf(result) }) + + test('useQuery - defining selectFromResult separately', () => { + const selectFromResult = ( + result: TypedUseQueryStateResult<string, void, typeof baseQuery>, + ) => ({ x: true }) + + const result = api.endpoints.getTest.useQuery(undefined, { + selectFromResult, + }) + + expectTypeOf(result).toEqualTypeOf< + TypedUseQueryHookResult< + string, + void, + typeof baseQuery, + ReturnType<typeof selectFromResult> + > + >() + }) + + test('useMutation - defining selectFromResult separately', () => { + const selectFromResult = ( + result: Omit< + TypedUseMutationResult<string, void, typeof baseQuery>, + 'reset' | 'originalArgs' + >, + ) => ({ x: true }) + + const [trigger, result] = api.endpoints.mutation.useMutation({ + selectFromResult, + }) + expectTypeOf(result).toEqualTypeOf< + TypedUseMutationResult< + string, + void, + typeof baseQuery, + ReturnType<typeof selectFromResult> + > + >() + }) })