updux => ts

typescript
Yanick Champoux 2019-10-23 17:47:43 -04:00
parent 76a75c9120
commit f0e3b15fa4
6 changed files with 50 additions and 38 deletions

View File

@ -1,5 +1,5 @@
import fp from 'lodash/fp';
import { Action } from '../types';
import { Action, ActionPayloadGenerator, Dictionary } from '../types';
interface ActionCreator {
( ...args: any[] ): Action;
@ -16,27 +16,25 @@ function actionFor(type:string) {
return creator;
}
export default function buildActions(
creators : { [action: string]: Function } = {},
mutations = {},
effects = {},
subActions = [],
) {
type ActionPair = [ string, ActionCreator ];
function buildActions(
generators : Dictionary<ActionPayloadGenerator> = {},
actionNames: string[] = [],
subActions : ActionPair[] = [],
):Dictionary<ActionCreator> {
// priority => generics => generic subs => craft subs => creators
const [ crafted, generic ] = fp.partition(
([type,f]) => !f._genericAction
)( fp.flatten( subActions.map( x => Object.entries(x) ) ).filter(
([_,f]) => f
) )
)( subActions );
const actions = [
...([ ...Object.keys(mutations), ...Object.keys(effects) ]
.map( type => [ type, actionFor(type) ] )),
...(actionNames.map( type => [ type, actionFor(type) ] )),
...generic,
...crafted,
...Object.entries(creators).map(
...Object.entries(generators).map(
([type, payload]: [ string, Function ]) => [type, (...args: any) => ({ type, payload: payload(...args) })]
),
];
@ -44,3 +42,5 @@ export default function buildActions(
return fp.fromPairs(actions);
}
export default buildActions;

View File

@ -1,9 +1,11 @@
import fp from 'lodash/fp';
import { Dictionary } from '../types';
function buildInitial<S extends object>( initial?: Partial<S>, subduxes?: Partial<S> ): S;
function buildInitial<S extends number|string|boolean>( initial: S, subduxes?: Dictionary<undefined> ): S;
function buildInitial<S extends object>( initial?: Partial<S>, subduxes?: Partial<S> ): S extends object ? S : never;
function buildInitial(
initial = {},
subduxes = {} ,
initial : any = {},
subduxes : any = {} ,
) {
return fp.isPlainObject(initial) ? fp.mergeAll([subduxes, initial]) : initial;
}

View File

@ -12,14 +12,9 @@ const MiddlewareFor = (type: any, mw: Middleware ): Middleware => api => next =>
type Next = (action: Action) => any;
function buildMiddleware(
effects: Dictionary<Middleware>,
actions: Dictionary<ActionCreator>,
subMiddlewares: Middleware[],
): Middleware
function buildMiddleware(
effects = {},
actions = {},
subduxes = {},
effects : Dictionary<Middleware>= {},
actions : Dictionary<ActionCreator>= {},
subMiddlewares :Middleware[] = [],
) {
return (api: any) => {
for (let type in actions) {
@ -31,7 +26,7 @@ function buildMiddleware(
...fp.toPairs(effects).map(([type, effect]) =>
MiddlewareFor(type,effect as Middleware)
),
...fp.map('middleware', subduxes),
...subMiddlewares
]
.filter(x => x)
.reduceRight((next, mw) => mw(api)(next), original_next);

View File

@ -1,8 +1,8 @@
import fp from 'lodash/fp';
import { Dictionary, Mutation, Action } from '../types';
import { Dictionary, Mutation, Action, Upreducer } from '../types';
function buildUpreducer<S>(initial: S, mutations: Dictionary<Mutation<S>> ) {
function buildUpreducer<S>(initial: S, mutations: Dictionary<Mutation<S>> ): Upreducer<S> {
return (action :Action) => (state: S) => {
if (state === null) state = initial;

View File

@ -9,11 +9,12 @@ export type Dictionary<T> = { [key: string]: T };
export type Mutation<S=any> = (payload: any, action: Action) => (state: S) => S ;
type ActionPayloadGenerator = (...args:any[]) => any;
export type ActionPayloadGenerator = (...args:any[]) => any;
export type ActionCreator = (...args: any[] ) => Action;
export type UpduxConfig = Partial<{
export type UpduxConfig<S=any> = Partial<{
initial: S,
subduxes: {},
actions: {
[ type: string ]: ActionPayloadGenerator
@ -21,3 +22,5 @@ export type UpduxConfig = Partial<{
mutations: any,
effects: any,
}>;
export type Upreducer<S=any> = (action:Action) => (state:S) => S;

View File

@ -6,15 +6,28 @@ import buildMutations from './buildMutations';
import buildCreateStore from './buildCreateStore';
import buildMiddleware from './buildMiddleware';
import buildUpreducer from './buildUpreducer';
import { UpduxConfig, Dictionary, Action, ActionCreator } from './types';
import { UpduxConfig, Dictionary, Action, ActionCreator, Mutation, Upreducer } from './types';
import { Middleware } from 'redux';
export class Updux {
export class Updux<S=any> {
subduxes: Dictionary<Updux>;
actions: Dictionary<ActionCreator>
initial: S;
mutations: Dictionary<Mutation>;
upreducer: Upreducer<S>;
reducer: (state:S|undefined,action:Action) => S;
middleware: Middleware;
createStore: Function;
constructor(config: UpduxConfig) {
this.subduxes = fp.mapValues(
@ -24,12 +37,11 @@ export class Updux {
this.actions = buildActions(
config.actions,
config.mutations,
config.effects,
Object.values( this.subduxes ).map( ({actions}) => actions ),
[ ...Object.keys(config.mutations||{}), ...Object.keys(config.effects||{} ) ],
fp.flatten( Object.values( this.subduxes ).map( ({actions}:Updux) => Object.entries(actions) ) ),
)
this.initial = buildInitial(
this.initial = buildInitial<any>(
config.initial, fp.mapValues( ({initial}) => initial )(this.subduxes)
);
@ -42,16 +54,16 @@ export class Updux {
);
this.reducer = (state,action) => {
return this.upreducer(action)(state);
return this.upreducer(action)(state as S);
}
this.middleware = buildMiddleware(
config.effects,
this.actions,
config.subduxes,
Object.values(this.subduxes).map( sd => sd.middleware )
);
this.createStore = buildCreateStore(this.reducer,this.initial,this.middleware,this.actions);
this.createStore = buildCreateStore<S>(this.reducer,this.initial,this.middleware,this.actions);
}
}