From dca9691d7d5cde897e109135a7626422b1e04f96 Mon Sep 17 00:00:00 2001 From: Jerko Steiner Date: Thu, 1 Aug 2019 15:51:59 +0700 Subject: [PATCH] Add ability to easily create redux middleware for async actions --- packages/jsonrpc/src/redux.test.ts | 33 ++++++++++++++++++++++----- packages/jsonrpc/src/redux.ts | 31 ++++++++++++++++++++++++- packages/jsonrpc/src/types.ts | 36 ++++++++++++++++++------------ 3 files changed, 79 insertions(+), 21 deletions(-) diff --git a/packages/jsonrpc/src/redux.test.ts b/packages/jsonrpc/src/redux.test.ts index 7b1698f..4e6d646 100644 --- a/packages/jsonrpc/src/redux.test.ts +++ b/packages/jsonrpc/src/redux.test.ts @@ -6,11 +6,11 @@ import bodyParser from 'body-parser' import express from 'express' import {AddressInfo} from 'net' import {Server} from 'http' -import {createReduxClient} from './redux' +import {createReduxClient, createReducer} from './redux' import {createRemoteClient} from './remote' import {jsonrpc} from './express' import {keys} from 'ts-transformer-keys' -import {TActionCreators, TAllActions} from './types' +import {TPendingActions, TAllActions} from './types' describe('createReduxClient', () => { @@ -73,9 +73,33 @@ describe('createReduxClient', () => { // type R = T extends (...args: any[]) => infer RV ? RV : never type Client = typeof client - type ActionCreators = TActionCreators + type ActionCreators = TPendingActions type AllActions = TAllActions + const defaultState = { + sum: 1, + } + + const create = createReducer('myService', defaultState) + ((state, action) => { + switch (action.method) { + case 'add': + const r1: number = action.payload + return state + case 'addAsync': + const r2: number = action.payload + return state + case 'addStringsAsync': + const r3: string = action.payload + return state + case 'addWithContext': + const r4: number = action.payload + return state + default: + return state + } + }) + function handleAction(state: any, action: AllActions) { if (action.type !== 'myService') { return @@ -99,9 +123,6 @@ describe('createReduxClient', () => { } } - // type Values = T[keyof T] - // type C = ReturnType> - return client } diff --git a/packages/jsonrpc/src/redux.ts b/packages/jsonrpc/src/redux.ts index 0c3dd47..0c2f660 100644 --- a/packages/jsonrpc/src/redux.ts +++ b/packages/jsonrpc/src/redux.ts @@ -1,4 +1,10 @@ -import {TAsyncified, TReduxed} from './types' +import { + IReduxed, + TAsyncified, + TReduxed, + TResolvedActions, + TAllActions, +} from './types' import {createRemoteClient} from './remote' export function createReduxClient( @@ -20,3 +26,26 @@ export function createReduxClient( return service as TReduxed } + +export const createReducer = ( + actionType: ActionType, + defaultState: State, +) => >( + handleAction: (state: State, action: TResolvedActions) => State, +) => (state: State = defaultState, action?: TAllActions): State => { + if (!action) { + return state + } + if (action.type !== actionType) { + return state + } + if (action.status === 'pending') { + // TODO handle loading + return state + } + if (action.status === 'rejected') { + // TODO handle rejected + return state + } + return handleAction(state, action) +} diff --git a/packages/jsonrpc/src/types.ts b/packages/jsonrpc/src/types.ts index 46666b6..60d5f0e 100644 --- a/packages/jsonrpc/src/types.ts +++ b/packages/jsonrpc/src/types.ts @@ -2,6 +2,7 @@ type ArgumentTypes = T extends (...args: infer U) => infer R ? U : never type RetType = T extends (...args: any[]) => infer R ? R : never type UnwrapHOC = T extends (...args: any[]) => infer R ? R : T +type UnwrapPromise = T extends Promise ? V : T type RetProm = T extends Promise ? T : Promise type PromisifyReturnType = (...a: ArgumentTypes) => RetProm>> @@ -12,19 +13,13 @@ export type TAsyncified = { [K in keyof T]: PromisifyReturnType } +export interface IReduxed { + [key: string]: (...a: any[]) => IRPCPendingAction +} + export type TReduxed = { - // [K in keyof T]: (...a: ArgumentTypes) => { - // type: ActionType - // payload: RetProm>> - // method: K - // status: 'pending' - // } - // [K in keyof T]: (...a: ArgumentTypes) => - // IPendingAction>>, ActionType> & { - // method: K, - // } [K in keyof T]: (...a: ArgumentTypes) => - IRPCPendingAction>, ActionType, K> + IRPCPendingAction>>, ActionType, K> } export interface IRPCPendingAction< @@ -45,6 +40,13 @@ export interface IRPCRejectedAction< method: Method } +export type TRPCAction< + T, ActionType extends string, Method extends string | number | symbol +> = + IRPCPendingAction + | IRPCResolvedAction + | IRPCRejectedAction + export type TResolved = A extends IRPCPendingAction ? IRPCResolvedAction @@ -55,7 +57,13 @@ export type TRejected = ? IRPCRejectedAction : never +export type TPending = + A extends IRPCPendingAction + ? IRPCPendingAction + : never + type Values = T[keyof T] -export type TActionCreators = RetType> -export type TAllActions = TActionCreators - | TResolved> | TRejected> +export type TPendingActions = TPending>> +export type TResolvedActions = TResolved> +export type TAllActions = TPendingActions + | TResolvedActions | TRejected>