Add ability to easily create redux middleware for async actions
This commit is contained in:
parent
fa27dda530
commit
dca9691d7d
@ -6,11 +6,11 @@ import bodyParser from 'body-parser'
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import {AddressInfo} from 'net'
|
import {AddressInfo} from 'net'
|
||||||
import {Server} from 'http'
|
import {Server} from 'http'
|
||||||
import {createReduxClient} from './redux'
|
import {createReduxClient, createReducer} from './redux'
|
||||||
import {createRemoteClient} from './remote'
|
import {createRemoteClient} from './remote'
|
||||||
import {jsonrpc} from './express'
|
import {jsonrpc} from './express'
|
||||||
import {keys} from 'ts-transformer-keys'
|
import {keys} from 'ts-transformer-keys'
|
||||||
import {TActionCreators, TAllActions} from './types'
|
import {TPendingActions, TAllActions} from './types'
|
||||||
|
|
||||||
describe('createReduxClient', () => {
|
describe('createReduxClient', () => {
|
||||||
|
|
||||||
@ -73,9 +73,33 @@ describe('createReduxClient', () => {
|
|||||||
// type R<T> = T extends (...args: any[]) => infer RV ? RV : never
|
// type R<T> = T extends (...args: any[]) => infer RV ? RV : never
|
||||||
|
|
||||||
type Client = typeof client
|
type Client = typeof client
|
||||||
type ActionCreators = TActionCreators<typeof client>
|
type ActionCreators = TPendingActions<typeof client>
|
||||||
type AllActions = TAllActions<typeof client>
|
type AllActions = TAllActions<typeof client>
|
||||||
|
|
||||||
|
const defaultState = {
|
||||||
|
sum: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
const create = createReducer('myService', defaultState)
|
||||||
|
<typeof client>((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) {
|
function handleAction(state: any, action: AllActions) {
|
||||||
if (action.type !== 'myService') {
|
if (action.type !== 'myService') {
|
||||||
return
|
return
|
||||||
@ -99,9 +123,6 @@ describe('createReduxClient', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// type Values<T> = T[keyof T]
|
|
||||||
// type C = ReturnType<Values<typeof client>>
|
|
||||||
|
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
import {TAsyncified, TReduxed} from './types'
|
import {
|
||||||
|
IReduxed,
|
||||||
|
TAsyncified,
|
||||||
|
TReduxed,
|
||||||
|
TResolvedActions,
|
||||||
|
TAllActions,
|
||||||
|
} from './types'
|
||||||
import {createRemoteClient} from './remote'
|
import {createRemoteClient} from './remote'
|
||||||
|
|
||||||
export function createReduxClient<T, ActionType extends string>(
|
export function createReduxClient<T, ActionType extends string>(
|
||||||
@ -20,3 +26,26 @@ export function createReduxClient<T, ActionType extends string>(
|
|||||||
|
|
||||||
return service as TReduxed<T, ActionType>
|
return service as TReduxed<T, ActionType>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const createReducer = <ActionType extends string, State>(
|
||||||
|
actionType: ActionType,
|
||||||
|
defaultState: State,
|
||||||
|
) => <R extends IReduxed<ActionType>>(
|
||||||
|
handleAction: (state: State, action: TResolvedActions<R>) => State,
|
||||||
|
) => (state: State = defaultState, action?: TAllActions<R>): 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)
|
||||||
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ type ArgumentTypes<T> =
|
|||||||
T extends (...args: infer U) => infer R ? U : never
|
T extends (...args: infer U) => infer R ? U : never
|
||||||
type RetType<T> = T extends (...args: any[]) => infer R ? R : never
|
type RetType<T> = T extends (...args: any[]) => infer R ? R : never
|
||||||
type UnwrapHOC<T> = T extends (...args: any[]) => infer R ? R : T
|
type UnwrapHOC<T> = T extends (...args: any[]) => infer R ? R : T
|
||||||
|
type UnwrapPromise<T> = T extends Promise<infer V> ? V : T
|
||||||
type RetProm<T> = T extends Promise<any> ? T : Promise<T>
|
type RetProm<T> = T extends Promise<any> ? T : Promise<T>
|
||||||
type PromisifyReturnType<T> = (...a: ArgumentTypes<T>) =>
|
type PromisifyReturnType<T> = (...a: ArgumentTypes<T>) =>
|
||||||
RetProm<UnwrapHOC<RetType<T>>>
|
RetProm<UnwrapHOC<RetType<T>>>
|
||||||
@ -12,19 +13,13 @@ export type TAsyncified<T> = {
|
|||||||
[K in keyof T]: PromisifyReturnType<T[K]>
|
[K in keyof T]: PromisifyReturnType<T[K]>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IReduxed<ActionType extends string> {
|
||||||
|
[key: string]: (...a: any[]) => IRPCPendingAction<any, ActionType, typeof key>
|
||||||
|
}
|
||||||
|
|
||||||
export type TReduxed<T, ActionType extends string> = {
|
export type TReduxed<T, ActionType extends string> = {
|
||||||
// [K in keyof T]: (...a: ArgumentTypes<T[K]>) => {
|
|
||||||
// type: ActionType
|
|
||||||
// payload: RetProm<UnwrapHOC<RetType<T[K]>>>
|
|
||||||
// method: K
|
|
||||||
// status: 'pending'
|
|
||||||
// }
|
|
||||||
// [K in keyof T]: (...a: ArgumentTypes<T[K]>) =>
|
|
||||||
// IPendingAction<RetProm<UnwrapHOC<RetType<T[K]>>>, ActionType> & {
|
|
||||||
// method: K,
|
|
||||||
// }
|
|
||||||
[K in keyof T]: (...a: ArgumentTypes<T[K]>) =>
|
[K in keyof T]: (...a: ArgumentTypes<T[K]>) =>
|
||||||
IRPCPendingAction<UnwrapHOC<RetType<T[K]>>, ActionType, K>
|
IRPCPendingAction<UnwrapPromise<UnwrapHOC<RetType<T[K]>>>, ActionType, K>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRPCPendingAction<
|
export interface IRPCPendingAction<
|
||||||
@ -45,6 +40,13 @@ export interface IRPCRejectedAction<
|
|||||||
method: Method
|
method: Method
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TRPCAction<
|
||||||
|
T, ActionType extends string, Method extends string | number | symbol
|
||||||
|
> =
|
||||||
|
IRPCPendingAction<T, ActionType, Method>
|
||||||
|
| IRPCResolvedAction<T, ActionType, Method>
|
||||||
|
| IRPCRejectedAction<ActionType, Method>
|
||||||
|
|
||||||
export type TResolved<A> =
|
export type TResolved<A> =
|
||||||
A extends IRPCPendingAction<infer T, infer ActionType, infer Method>
|
A extends IRPCPendingAction<infer T, infer ActionType, infer Method>
|
||||||
? IRPCResolvedAction<T, ActionType, Method>
|
? IRPCResolvedAction<T, ActionType, Method>
|
||||||
@ -55,7 +57,13 @@ export type TRejected<A> =
|
|||||||
? IRPCRejectedAction<ActionType, Method>
|
? IRPCRejectedAction<ActionType, Method>
|
||||||
: never
|
: never
|
||||||
|
|
||||||
|
export type TPending<A> =
|
||||||
|
A extends IRPCPendingAction<infer T, infer ActionType, infer Method>
|
||||||
|
? IRPCPendingAction<T, ActionType, Method>
|
||||||
|
: never
|
||||||
|
|
||||||
type Values<T> = T[keyof T]
|
type Values<T> = T[keyof T]
|
||||||
export type TActionCreators<T> = RetType<Values<T>>
|
export type TPendingActions<T> = TPending<RetType<Values<T>>>
|
||||||
export type TAllActions<T> = TActionCreators<T>
|
export type TResolvedActions<T> = TResolved<TPendingActions<T>>
|
||||||
| TResolved<TActionCreators<T>> | TRejected<TActionCreators<T>>
|
export type TAllActions<T> = TPendingActions<T>
|
||||||
|
| TResolvedActions<T> | TRejected<TPendingActions<T>>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user