diff --git a/docs/api/createListenerMiddleware.mdx b/docs/api/createListenerMiddleware.mdx index 050fbd20b9..a805e2ebe9 100644 --- a/docs/api/createListenerMiddleware.mdx +++ b/docs/api/createListenerMiddleware.mdx @@ -488,11 +488,14 @@ To fix this, the middleware provides types for defining "pre-typed" versions of import { createListenerMiddleware, addListener } from '@reduxjs/toolkit' import type { RootState, AppDispatch } from './store' +declare type ExtraArgument = {foo: string}; + export const listenerMiddleware = createListenerMiddleware() export const startAppListening = listenerMiddleware.startListening.withTypes< RootState, - AppDispatch + AppDispatch, + ExtraArgument >() export const addAppListener = addListener.withTypes() diff --git a/packages/toolkit/src/listenerMiddleware/tests/listenerMiddleware.withTypes.test-d.ts b/packages/toolkit/src/listenerMiddleware/tests/listenerMiddleware.withTypes.test-d.ts index 6756144579..ae6fd6c46d 100644 --- a/packages/toolkit/src/listenerMiddleware/tests/listenerMiddleware.withTypes.test-d.ts +++ b/packages/toolkit/src/listenerMiddleware/tests/listenerMiddleware.withTypes.test-d.ts @@ -64,6 +64,7 @@ type AppThunk = ThunkAction< unknown, Action > +type ExtraArgument = { foo: string } describe('listenerMiddleware.withTypes()', () => { const listenerMiddleware = createListenerMiddleware() @@ -77,11 +78,12 @@ describe('listenerMiddleware.withTypes()', () => { test('startListening.withTypes', () => { const startAppListening = listenerMiddleware.startListening.withTypes< RootState, - AppDispatch + AppDispatch, + ExtraArgument >() expectTypeOf(startAppListening).toEqualTypeOf< - TypedStartListening + TypedStartListening >() startAppListening({ @@ -102,6 +104,8 @@ describe('listenerMiddleware.withTypes()', () => { expectTypeOf(stateCurrent).toEqualTypeOf() + expectTypeOf(listenerApi.extra).toEqualTypeOf() + timeout = 1 takeResult = await listenerApi.take(increment.match, timeout) @@ -111,10 +115,10 @@ describe('listenerMiddleware.withTypes()', () => { }) test('addListener.withTypes', () => { - const addAppListener = addListener.withTypes() + const addAppListener = addListener.withTypes() expectTypeOf(addAppListener).toEqualTypeOf< - TypedAddListener + TypedAddListener >() store.dispatch( @@ -126,27 +130,30 @@ describe('listenerMiddleware.withTypes()', () => { expectTypeOf(state).toEqualTypeOf() expectTypeOf(listenerApi.dispatch).toEqualTypeOf() + + expectTypeOf(listenerApi.extra).toEqualTypeOf() }, }), ) }) test('removeListener.withTypes', () => { - const removeAppListener = removeListener.withTypes() + const removeAppListener = removeListener.withTypes() expectTypeOf(removeAppListener).toEqualTypeOf< - TypedRemoveListener + TypedRemoveListener >() }) test('stopListening.withTypes', () => { const stopAppListening = listenerMiddleware.stopListening.withTypes< RootState, - AppDispatch + AppDispatch, + ExtraArgument >() expectTypeOf(stopAppListening).toEqualTypeOf< - TypedStopListening + TypedStopListening >() }) }) diff --git a/packages/toolkit/src/listenerMiddleware/tests/listenerMiddleware.withTypes.test.ts b/packages/toolkit/src/listenerMiddleware/tests/listenerMiddleware.withTypes.test.ts index 84bcf1ff2c..8d9da271f8 100644 --- a/packages/toolkit/src/listenerMiddleware/tests/listenerMiddleware.withTypes.test.ts +++ b/packages/toolkit/src/listenerMiddleware/tests/listenerMiddleware.withTypes.test.ts @@ -55,21 +55,25 @@ type AppThunk = ThunkAction< Action > +type ExtraArgument = { foo: string } + const listenerMiddleware = createListenerMiddleware() const startAppListening = listenerMiddleware.startListening.withTypes< RootState, - AppDispatch + AppDispatch, + ExtraArgument >() const stopAppListening = listenerMiddleware.stopListening.withTypes< RootState, - AppDispatch + AppDispatch, + ExtraArgument >() -const addAppListener = addListener.withTypes() +const addAppListener = addListener.withTypes() -const removeAppListener = removeListener.withTypes() +const removeAppListener = removeListener.withTypes() describe('startAppListening.withTypes', () => { test('should return startListening', () => { diff --git a/packages/toolkit/src/listenerMiddleware/types.ts b/packages/toolkit/src/listenerMiddleware/types.ts index e3cba71621..b5980e1085 100644 --- a/packages/toolkit/src/listenerMiddleware/types.ts +++ b/packages/toolkit/src/listenerMiddleware/types.ts @@ -506,11 +506,12 @@ export type RemoveListenerOverloads< unknown, UnknownAction >, + ExtraArgument = unknown, > = AddListenerOverloads< boolean, StateType, DispatchType, - any, + ExtraArgument, UnsubscribeListenerOptions > @@ -551,22 +552,23 @@ export type TypedAddListener< > & { /** * Creates a "pre-typed" version of `addListener` - * where the `state` and `dispatch` types are predefined. + * where the `state`, `dispatch` and `extra` types are predefined. * - * This allows you to set the `state` and `dispatch` types once, + * This allows you to set the `state`, `dispatch` and `extra` types once, * eliminating the need to specify them with every `addListener` call. * - * @returns A pre-typed `addListener` with the state and dispatch types already defined. + * @returns A pre-typed `addListener` with the state, dispatch and extra types already defined. * * @example * ```ts * import { addListener } from '@reduxjs/toolkit' * - * export const addAppListener = addListener.withTypes() + * export const addAppListener = addListener.withTypes() * ``` * * @template OverrideStateType - The specific type of state the middleware listener operates on. * @template OverrideDispatchType - The specific type of the dispatch function. + * @template OverrideExtraArgument - The specific type of the extra object. * * @since 2.1.0 */ @@ -576,8 +578,9 @@ export type TypedAddListener< OverrideStateType, unknown, UnknownAction - >, - >() => TypedAddListener + >, + OverrideExtraArgument = unknown, + >() => TypedAddListener } /** @@ -592,6 +595,7 @@ export type TypedRemoveListener< unknown, UnknownAction >, + ExtraArgument = unknown, Payload = ListenerEntry, T extends string = 'listenerMiddleware/remove', > = BaseActionCreator & @@ -599,27 +603,33 @@ export type TypedRemoveListener< PayloadAction, StateType, DispatchType, - any, + ExtraArgument, UnsubscribeListenerOptions > & { /** * Creates a "pre-typed" version of `removeListener` - * where the `state` and `dispatch` types are predefined. + * where the `state`, `dispatch` and `extra` types are predefined. * - * This allows you to set the `state` and `dispatch` types once, + * This allows you to set the `state`, `dispatch` and `extra` types once, * eliminating the need to specify them with every `removeListener` call. * - * @returns A pre-typed `removeListener` with the state and dispatch types already defined. + * @returns A pre-typed `removeListener` with the state, dispatch and extra + * types already defined. * * @example * ```ts * import { removeListener } from '@reduxjs/toolkit' * - * export const removeAppListener = removeListener.withTypes() + * export const removeAppListener = removeListener.withTypes< + * RootState, + * AppDispatch, + * ExtraArguments + * >() * ``` * * @template OverrideStateType - The specific type of state the middleware listener operates on. * @template OverrideDispatchType - The specific type of the dispatch function. + * @template OverrideExtraArgument - The specific type of the extra object. * * @since 2.1.0 */ @@ -630,7 +640,8 @@ export type TypedRemoveListener< unknown, UnknownAction >, - >() => TypedRemoveListener + OverrideExtraArgument = unknown, + >() => TypedRemoveListener } /** @@ -655,13 +666,13 @@ export type TypedStartListening< /** * Creates a "pre-typed" version of * {@linkcode ListenerMiddlewareInstance.startListening startListening} - * where the `state` and `dispatch` types are predefined. + * where the `state`, `dispatch` and `extra` types are predefined. * - * This allows you to set the `state` and `dispatch` types once, + * This allows you to set the `state`, `dispatch` and `extra` types once, * eliminating the need to specify them with every * {@linkcode ListenerMiddlewareInstance.startListening startListening} call. * - * @returns A pre-typed `startListening` with the state and dispatch types already defined. + * @returns A pre-typed `startListening` with the state, dispatch and extra types already defined. * * @example * ```ts @@ -671,12 +682,14 @@ export type TypedStartListening< * * export const startAppListening = listenerMiddleware.startListening.withTypes< * RootState, - * AppDispatch + * AppDispatch, + * ExtraArguments * >() * ``` * * @template OverrideStateType - The specific type of state the middleware listener operates on. * @template OverrideDispatchType - The specific type of the dispatch function. + * @template OverrideExtraArgument - The specific type of the extra object. * * @since 2.1.0 */ @@ -687,7 +700,8 @@ export type TypedStartListening< unknown, UnknownAction >, - >() => TypedStartListening + OverrideExtraArgument = unknown, + >() => TypedStartListening } /** @@ -702,17 +716,18 @@ export type TypedStopListening< unknown, UnknownAction >, -> = RemoveListenerOverloads & { + ExtraArgument = unknown, +> = RemoveListenerOverloads & { /** * Creates a "pre-typed" version of * {@linkcode ListenerMiddlewareInstance.stopListening stopListening} - * where the `state` and `dispatch` types are predefined. + * where the `state`, `dispatch` and `extra` types are predefined. * - * This allows you to set the `state` and `dispatch` types once, + * This allows you to set the `state`, `dispatch` and `extra` types once, * eliminating the need to specify them with every * {@linkcode ListenerMiddlewareInstance.stopListening stopListening} call. * - * @returns A pre-typed `stopListening` with the state and dispatch types already defined. + * @returns A pre-typed `stopListening` with the state, dispatch and extra types already defined. * * @example * ```ts @@ -722,12 +737,14 @@ export type TypedStopListening< * * export const stopAppListening = listenerMiddleware.stopListening.withTypes< * RootState, - * AppDispatch + * AppDispatch, + * ExtraArguments * >() * ``` * * @template OverrideStateType - The specific type of state the middleware listener operates on. * @template OverrideDispatchType - The specific type of the dispatch function. + * @template OverrideExtraArgument - The specific type of the extra object. * * @since 2.1.0 */ @@ -738,7 +755,8 @@ export type TypedStopListening< unknown, UnknownAction >, - >() => TypedStopListening + OverrideExtraArgument = unknown, + >() => TypedStopListening } /** @@ -753,19 +771,22 @@ export type TypedCreateListenerEntry< unknown, UnknownAction >, + ExtraArgument = unknown, > = AddListenerOverloads< ListenerEntry, StateType, - DispatchType + DispatchType, + ExtraArgument > & { /** * Creates a "pre-typed" version of `createListenerEntry` - * where the `state` and `dispatch` types are predefined. + * where the `state`, `dispatch` and `extra` types are predefined. * - * This allows you to set the `state` and `dispatch` types once, eliminating + * This allows you to set the `state`, `dispatch` and `extra` types once, eliminating * the need to specify them with every `createListenerEntry` call. * - * @returns A pre-typed `createListenerEntry` with the state and dispatch types already defined. + * @returns A pre-typed `createListenerEntry` with the state, dispatch and extra + * types already defined. * * @example * ```ts @@ -773,12 +794,14 @@ export type TypedCreateListenerEntry< * * export const createAppListenerEntry = createListenerEntry.withTypes< * RootState, - * AppDispatch + * AppDispatch, + * ExtraArguments * >() * ``` * * @template OverrideStateType - The specific type of state the middleware listener operates on. * @template OverrideDispatchType - The specific type of the dispatch function. + * @template OverrideExtraArgument - The specific type of the extra object. * * @since 2.1.0 */ @@ -789,7 +812,8 @@ export type TypedCreateListenerEntry< unknown, UnknownAction >, - >() => TypedStopListening + OverrideExtraArgument = unknown, + >() => TypedStopListening } /**