Skip to content

Commit dca6ab1

Browse files
committed
Clean up dead types and add some doc comments
1 parent 1c73295 commit dca6ab1

File tree

2 files changed

+26
-37
lines changed

2 files changed

+26
-37
lines changed

packages/action-listener-middleware/src/index.ts

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -59,25 +59,6 @@ function assertFunction(
5959
}
6060
}
6161

62-
export const hasMatchFunction = <T>(
63-
v: Matcher<T>
64-
): v is HasMatchFunction<T> => {
65-
return v && typeof (v as HasMatchFunction<T>).match === 'function'
66-
}
67-
68-
export const isActionCreator = (
69-
item: Function
70-
): item is TypedActionCreator<any> => {
71-
return (
72-
typeof item === 'function' &&
73-
typeof (item as any).type === 'string' &&
74-
hasMatchFunction(item as any)
75-
)
76-
}
77-
78-
/** @public */
79-
export type Matcher<T> = HasMatchFunction<T> | MatchFunction<T>
80-
8162
type Unsubscribe = () => void
8263

8364
type GuardedType<T> = T extends (x: any, ...args: unknown[]) => x is infer T
@@ -147,11 +128,15 @@ export interface CreateListenerMiddlewareOptions<ExtraArgument = unknown> {
147128
onError?: ListenerErrorHandler
148129
}
149130

131+
/**
132+
* The possible overloads and options for defining a listener. The return type of each function is specified as a generic arg, so the overloads can be reused for multiple different functions
133+
*/
150134
interface AddListenerOverloads<
151135
Return,
152136
S = unknown,
153137
D extends Dispatch = ThunkDispatch<S, unknown, AnyAction>
154138
> {
139+
/** Accepts a "listener predicate" that is also a TS type predicate for the action*/
155140
<MA extends AnyAction, LP extends ListenerPredicate<MA, S>>(
156141
options: {
157142
actionCreator?: never
@@ -161,6 +146,8 @@ interface AddListenerOverloads<
161146
listener: ActionListener<ListenerPredicateGuardedActionType<LP>, S, D>
162147
} & ActionListenerOptions
163148
): Return
149+
150+
/** Accepts an RTK action creator, like `incrementByAmount` */
164151
<C extends TypedActionCreator<any>>(
165152
options: {
166153
actionCreator: C
@@ -170,6 +157,8 @@ interface AddListenerOverloads<
170157
listener: ActionListener<ReturnType<C>, S, D>
171158
} & ActionListenerOptions
172159
): Return
160+
161+
/** Accepts a specific action type string */
173162
<T extends string>(
174163
options: {
175164
actionCreator?: never
@@ -179,6 +168,8 @@ interface AddListenerOverloads<
179168
listener: ActionListener<Action<T>, S, D>
180169
} & ActionListenerOptions
181170
): Return
171+
172+
/** Accepts an RTK matcher function, such as `incrementByAmount.match` */
182173
<MA extends AnyAction, M extends MatchFunction<MA>>(
183174
options: {
184175
actionCreator?: never
@@ -189,6 +180,7 @@ interface AddListenerOverloads<
189180
} & ActionListenerOptions
190181
): Return
191182

183+
/** Accepts a "listener predicate" that just returns a boolean, no type assertion */
192184
<LP extends AnyActionListenerPredicate<S>>(
193185
options: {
194186
actionCreator?: never
@@ -211,19 +203,22 @@ interface RemoveListenerOverloads<
211203
(type: string, listener: ActionListener<AnyAction, S, D>): boolean
212204
}
213205

206+
/** A "pre-typed" version of `addListenerAction`, so the listener args are well-typed */
214207
export type TypedAddListenerAction<
215208
S,
216209
D extends Dispatch<AnyAction> = ThunkDispatch<S, unknown, AnyAction>,
217210
Payload = ListenerEntry<S, D>,
218211
T extends string = 'actionListenerMiddleware/add'
219212
> = BaseActionCreator<Payload, T> &
220-
AddListenerOverloads<PayloadAction<Payload>, S, D>
213+
AddListenerOverloads<PayloadAction<Payload, T>, S, D>
221214

215+
/** A "pre-typed" version of `middleware.addListener`, so the listener args are well-typed */
222216
export type TypedAddListener<
223217
S,
224218
D extends Dispatch<AnyAction> = ThunkDispatch<S, unknown, AnyAction>
225219
> = AddListenerOverloads<Unsubscribe, S, D>
226220

221+
/** @internal An single listener entry */
227222
type ListenerEntry<
228223
S = unknown,
229224
D extends Dispatch<AnyAction> = Dispatch<AnyAction>
@@ -236,16 +231,13 @@ type ListenerEntry<
236231
predicate: ListenerPredicate<AnyAction, S>
237232
}
238233

234+
/** A "pre-typed" version of `createListenerEntry`, so the listener args are well-typed */
239235
export type TypedCreateListenerEntry<
240236
S,
241237
D extends Dispatch<AnyAction> = ThunkDispatch<S, unknown, AnyAction>
242238
> = AddListenerOverloads<ListenerEntry<S, D>, S, D>
243239

244-
export type TypedAddListenerPrepareFunction<
245-
S,
246-
D extends Dispatch<AnyAction> = ThunkDispatch<S, unknown, AnyAction>
247-
> = AddListenerOverloads<{ payload: ListenerEntry<S, D> }, S, D>
248-
240+
// A shorthand form of the accepted args, solely so that `createListenerEntry` has validly-typed conditional logic when checking the options contents
249241
type FallbackAddListenerOptions = (
250242
| { actionCreator: TypedActionCreator<string> }
251243
| { type: string }
@@ -254,6 +246,7 @@ type FallbackAddListenerOptions = (
254246
) &
255247
ActionListenerOptions & { listener: ActionListener<any, any, any> }
256248

249+
/** Accepts the possible options for creating a listener, and returns a formatted listener entry */
257250
export const createListenerEntry: TypedCreateListenerEntry<unknown> = (
258251
options: FallbackAddListenerOptions
259252
) => {
@@ -337,6 +330,7 @@ export const addListenerAction = createAction(
337330
'actionListenerMiddleware/add',
338331
function prepare(options: unknown) {
339332
const entry = createListenerEntry(
333+
// Fake out TS here
340334
options as Parameters<AddListenerOverloads<unknown>>[0]
341335
)
342336

@@ -407,14 +401,6 @@ export function createActionListenerMiddleware<
407401
D extends Dispatch<AnyAction> = ThunkDispatch<S, unknown, AnyAction>,
408402
ExtraArgument = unknown
409403
>(middlewareOptions: CreateListenerMiddlewareOptions<ExtraArgument> = {}) {
410-
type ListenerEntry = ActionListenerOptions & {
411-
id: string
412-
listener: ActionListener<any, S, D>
413-
unsubscribe: () => void
414-
type?: string
415-
predicate: ListenerPredicate<any, any>
416-
}
417-
418404
const listenerMap = new Map<string, ListenerEntry>()
419405
const { extra, onError = defaultErrorHandler } = middlewareOptions
420406

packages/action-listener-middleware/src/tests/listenerMiddleware.test.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@ import {
22
configureStore,
33
createAction,
44
createSlice,
5-
AnyAction,
65
isAnyOf,
7-
PayloadAction,
86
} from '@reduxjs/toolkit'
7+
8+
import type { AnyAction, PayloadAction, Action } from '@reduxjs/toolkit'
9+
910
import {
1011
createActionListenerMiddleware,
1112
createListenerEntry,
1213
addListenerAction,
1314
removeListenerAction,
15+
} from '../index'
16+
17+
import type {
1418
When,
1519
ActionListenerMiddlewareAPI,
16-
ActionListenerMiddleware,
17-
TypedCreateListenerEntry,
1820
TypedAddListenerAction,
1921
TypedAddListener,
2022
} from '../index'
@@ -345,6 +347,7 @@ describe('createActionListenerMiddleware', () => {
345347
listener,
346348
})
347349
)
350+
expectType<Action<'actionListenerMiddleware/add'>>(unsubscribe)
348351

349352
store.dispatch(testAction1('a'))
350353
// TODO This return type isn't correct

0 commit comments

Comments
 (0)