Skip to content

Commit be658bc

Browse files
committed
🏷️ Add proper typing for takeRequest & takeLatestRequest utils
1 parent 7acce57 commit be658bc

File tree

5 files changed

+48
-32
lines changed

5 files changed

+48
-32
lines changed

packages/@ackee/antonio-utils/README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ yarn add @ackee/antonio-utils -S
3737

3838
#### Parameters
3939

40-
- `actionTypes: Object`
40+
- `actionTypes: TakeRequest`
4141
- `REQUEST: ActionPattern` - action type that launches the saga
4242
- `CANCEL: ActionPattern` - action type that aborts the running saga
4343
- `saga(requestAction, signal: Signal): Function` - the actual API request is made here
@@ -65,11 +65,11 @@ export default function* () {
6565

6666
#### Parameters
6767

68-
- `params: TakeLatestRequest`
69-
- `REQUEST: ActionPattern` - action type that launches the saga
68+
- `params: TakeLatestRequest<RequestAction extends AnyAction, CancelAction extends AnyAction>`
69+
- `REQUEST: RequestAction['type']` - action type that launches the saga
7070
- `cancelTask<A extends AnyAction = AnyAction>(requestId: RequestId, action: A): A;` - Redux action that will cancel the
7171
running saga
72-
- `requestIdSelector?<A extends AnyAction = AnyAction>(action: A): RequestId;` - A function that receives request action as 1st arg. and returns unique ID of this action, e.g. user ID.
72+
- `cancelTask(requestId: RequestId, action: RequestAction): CancelAction;` - A function that receives request action as 1st arg. and returns unique ID of this action, e.g. user ID.
7373
- `saga(requestAction, signal: Signal): Function` - the actual API request is made here
7474

7575
#### Example

packages/@ackee/antonio-utils/src/saga-effects/takeLatestRequest.ts

+18-11
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
1+
import type { AnyAction } from 'redux';
12
import { takeEvery, put, spawn } from 'redux-saga/effects';
3+
24
import cancellableHandler from './utils/cancellableHandler';
35

46
import type { TakeLatestRequest, RequestHandler, RequestId } from '../types';
57

6-
export default function* takeLatestRequest(
7-
{ REQUEST, cancelTask, requestIdSelector }: TakeLatestRequest,
8-
requestHandler: RequestHandler,
8+
export default function* takeLatestRequest<
9+
RequestAction extends AnyAction = AnyAction,
10+
CancelAction extends AnyAction = AnyAction,
11+
>(
12+
{ REQUEST, cancelTask, requestIdSelector }: TakeLatestRequest<RequestAction, CancelAction>,
13+
requestHandler: RequestHandler<RequestAction>,
914
) {
1015
const runningTasks = new Set<RequestId>();
1116
const DEFAULT_REQUEST_ID = Symbol('DEFAULT_REQUEST_ID');
1217

13-
yield takeEvery(REQUEST, function* (action) {
18+
yield takeEvery(REQUEST, function* (action: RequestAction) {
1419
const requestId = requestIdSelector ? requestIdSelector(action) : DEFAULT_REQUEST_ID;
1520

1621
if (runningTasks.has(requestId)) {
1722
yield put(cancelTask(requestId, action));
1823
runningTasks.delete(requestId);
1924
}
2025

21-
yield spawn(cancellableHandler, {
22-
handler: requestHandler,
23-
handlerArg: action,
24-
CANCEL: cancelTask(requestId, action).type,
25-
onComplete() {
26-
runningTasks.delete(requestId);
27-
},
26+
yield spawn(function* () {
27+
yield* cancellableHandler<RequestAction, CancelAction['type']>({
28+
handler: requestHandler,
29+
handlerArg: action,
30+
CANCEL: cancelTask(requestId, action).type,
31+
onComplete() {
32+
runningTasks.delete(requestId);
33+
},
34+
});
2835
});
2936

3037
runningTasks.add(requestId);

packages/@ackee/antonio-utils/src/saga-effects/takeRequest.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1+
import type { AnyAction } from 'redux';
12
import { take } from 'redux-saga/effects';
23
import type { RequestHandler, TakeRequest } from '../types';
34
import cancellableHandler from './utils/cancellableHandler';
45

56
/**
67
* Blocking custom saga effect that can cancel the API request
78
*/
8-
export default function* takeRequest(actionTypes: TakeRequest, handler: RequestHandler) {
9+
export default function* takeRequest<RequestAction extends AnyAction = AnyAction>(
10+
actionTypes: TakeRequest,
11+
handler: RequestHandler<RequestAction>,
12+
) {
913
while (true) {
1014
/* @ts-ignore */
1115
const action = yield take(actionTypes.REQUEST);
1216

13-
yield cancellableHandler({
17+
yield cancellableHandler<RequestAction, typeof actionTypes['CANCEL']>({
1418
handler,
1519
handlerArg: action,
1620
CANCEL: actionTypes.CANCEL,

packages/@ackee/antonio-utils/src/saga-effects/utils/cancellableHandler.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
1+
import type { AnyAction } from 'redux';
12
import { call, take, race } from 'redux-saga/effects';
2-
import { CancellableHandler } from '../../types';
3+
import type { ActionPattern } from 'redux-saga/effects';
4+
import type { CancellableHandler } from '../../types';
35

46
if (!('AbortController' in window)) {
57
require('abortcontroller-polyfill/dist/abortcontroller-polyfill-only.js');
68
}
79

810
const noop = function* () {};
911

10-
export default function* cancellableHandler({ handlerArg, CANCEL, handler, onComplete = noop }: CancellableHandler) {
12+
export default function* cancellableHandler<RequestAction extends AnyAction, CancelActionType extends ActionPattern>({
13+
handlerArg,
14+
CANCEL,
15+
handler,
16+
onComplete = noop,
17+
}: CancellableHandler<RequestAction, CancelActionType>) {
1118
const controller = new AbortController();
1219

1320
function* tasks() {

packages/@ackee/antonio-utils/src/types.ts

+11-13
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
1-
import { AnyAction } from 'redux';
1+
import type { AnyAction } from 'redux';
22
import type { ActionPattern } from 'redux-saga/effects';
33

4-
type Fn = (...args: any[]) => any;
4+
export type RequestHandler<RequestAction> = (requestAction: RequestAction, signal: AbortSignal) => any;
55

6-
export type RequestHandler<A extends AnyAction = AnyAction> = (requestAction: A, signal: AbortSignal) => any;
7-
8-
export interface CancellableHandler {
9-
handlerArg: any;
10-
CANCEL: ActionPattern;
11-
handler: RequestHandler;
12-
onComplete?: Fn;
6+
export interface CancellableHandler<RequestAction extends AnyAction, CancelActionType = AnyAction['type']> {
7+
handlerArg: RequestAction;
8+
CANCEL: CancelActionType;
9+
handler: RequestHandler<RequestAction>;
10+
onComplete?(...args: any[]): void;
1311
}
1412

1513
export type RequestId = symbol | string | number;
1614

17-
export interface TakeLatestRequest {
18-
REQUEST: ActionPattern;
19-
cancelTask<A extends AnyAction = AnyAction>(requestId: RequestId, action: A): A;
20-
requestIdSelector?<A extends AnyAction = AnyAction>(action: A): RequestId;
15+
export interface TakeLatestRequest<RequestAction extends AnyAction, CancelAction extends AnyAction> {
16+
REQUEST: RequestAction['type'];
17+
cancelTask(requestId: RequestId, action: RequestAction): CancelAction;
18+
requestIdSelector?(action: RequestAction): RequestId;
2119
}
2220

2321
export interface TakeRequest {

0 commit comments

Comments
 (0)