Add ability to infer jsonrpc redux action types

This commit is contained in:
Jerko Steiner 2019-08-01 13:57:51 +07:00
parent 33c401dbcb
commit fa27dda530
2 changed files with 87 additions and 7 deletions

View File

@ -10,12 +10,14 @@ import {createReduxClient} from './redux'
import {createRemoteClient} from './remote'
import {jsonrpc} from './express'
import {keys} from 'ts-transformer-keys'
import {TActionCreators, TAllActions} from './types'
describe('createReduxClient', () => {
interface IService {
add(a: number, b: number): number
addAsync(a: number, b: number): Promise<number>
addStringsAsync(a: string, b: string): Promise<string>
addWithContext(a: number, b: number): (ctx: IContext) => number
addAsyncWithContext(a: number, b: number): (ctx: IContext) =>
Promise<number>
@ -32,6 +34,9 @@ describe('createReduxClient', () => {
addAsync(a: number, b: number) {
return new Promise<number>(resolve => resolve(a + b))
}
addStringsAsync(a: string, b: string) {
return new Promise<string>(resolve => resolve(a + b))
}
addWithContext = (a: number, b: number) => (ctx: IContext) =>
a + b + ctx.userId
addAsyncWithContext = (a: number, b: number) => (ctx: IContext) =>
@ -63,7 +68,41 @@ describe('createReduxClient', () => {
function getClient() {
const remoteClient = createRemoteClient<IService>(
baseUrl, '/service', keys<IService>())
return createReduxClient(remoteClient, 'myService')
const client = createReduxClient(remoteClient, 'myService')
// type R<T> = T extends (...args: any[]) => infer RV ? RV : never
type Client = typeof client
type ActionCreators = TActionCreators<typeof client>
type AllActions = TAllActions<typeof client>
function handleAction(state: any, action: AllActions) {
if (action.type !== 'myService') {
return
}
switch (action.method) {
case 'add':
switch (action.status) {
case 'pending':
const p1: Promise<number> = action.payload
return
case 'rejected':
const p2: Error = action.payload
return
case 'resolved':
const p3: number = action.payload
return
}
case 'addAsync':
// case 'addAsync1234':
// case
}
}
// type Values<T> = T[keyof T]
// type C = ReturnType<Values<typeof client>>
return client
}
describe('action creators', () => {

View File

@ -6,15 +6,56 @@ type RetProm<T> = T extends Promise<any> ? T : Promise<T>
type PromisifyReturnType<T> = (...a: ArgumentTypes<T>) =>
RetProm<UnwrapHOC<RetType<T>>>
import {IPendingAction, IResolvedAction, IRejectedAction} from '@rondo/client'
export type TAsyncified<T> = {
[K in keyof T]: PromisifyReturnType<T[K]>
}
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]>) => {
// 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]>) =>
IRPCPendingAction<UnwrapHOC<RetType<T[K]>>, ActionType, K>
}
export interface IRPCPendingAction<
T, ActionType extends string, Method extends string | number | symbol
> extends IPendingAction<T, ActionType> {
method: Method
}
export interface IRPCResolvedAction<
T, ActionType extends string, Method extends string | symbol | number
> extends IResolvedAction<T, ActionType> {
method: Method
}
export interface IRPCRejectedAction<
ActionType extends string, Method extends string | symbol | number
> extends IRejectedAction<ActionType> {
method: Method
}
export type TResolved<A> =
A extends IRPCPendingAction<infer T, infer ActionType, infer Method>
? IRPCResolvedAction<T, ActionType, Method>
: never
export type TRejected<A> =
A extends IRPCPendingAction<infer T, infer ActionType, infer Method>
? IRPCRejectedAction<ActionType, Method>
: never
type Values<T> = T[keyof T]
export type TActionCreators<T> = RetType<Values<T>>
export type TAllActions<T> = TActionCreators<T>
| TResolved<TActionCreators<T>> | TRejected<TActionCreators<T>>