updux => ts

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

View File

@ -1,9 +1,11 @@
import fp from 'lodash/fp'; 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( function buildInitial(
initial = {}, initial : any = {},
subduxes = {} , subduxes : any = {} ,
) { ) {
return fp.isPlainObject(initial) ? fp.mergeAll([subduxes, initial]) : initial; 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; type Next = (action: Action) => any;
function buildMiddleware( function buildMiddleware(
effects: Dictionary<Middleware>, effects : Dictionary<Middleware>= {},
actions: Dictionary<ActionCreator>, actions : Dictionary<ActionCreator>= {},
subMiddlewares: Middleware[], subMiddlewares :Middleware[] = [],
): Middleware
function buildMiddleware(
effects = {},
actions = {},
subduxes = {},
) { ) {
return (api: any) => { return (api: any) => {
for (let type in actions) { for (let type in actions) {
@ -31,7 +26,7 @@ function buildMiddleware(
...fp.toPairs(effects).map(([type, effect]) => ...fp.toPairs(effects).map(([type, effect]) =>
MiddlewareFor(type,effect as Middleware) MiddlewareFor(type,effect as Middleware)
), ),
...fp.map('middleware', subduxes), ...subMiddlewares
] ]
.filter(x => x) .filter(x => x)
.reduceRight((next, mw) => mw(api)(next), original_next); .reduceRight((next, mw) => mw(api)(next), original_next);

View File

@ -1,8 +1,8 @@
import fp from 'lodash/fp'; 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) => { return (action :Action) => (state: S) => {
if (state === null) state = initial; 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 ; 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 ActionCreator = (...args: any[] ) => Action;
export type UpduxConfig = Partial<{ export type UpduxConfig<S=any> = Partial<{
initial: S,
subduxes: {}, subduxes: {},
actions: { actions: {
[ type: string ]: ActionPayloadGenerator [ type: string ]: ActionPayloadGenerator
@ -21,3 +22,5 @@ export type UpduxConfig = Partial<{
mutations: any, mutations: any,
effects: 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 buildCreateStore from './buildCreateStore';
import buildMiddleware from './buildMiddleware'; import buildMiddleware from './buildMiddleware';
import buildUpreducer from './buildUpreducer'; 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>; subduxes: Dictionary<Updux>;
actions: Dictionary<ActionCreator> 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) { constructor(config: UpduxConfig) {
this.subduxes = fp.mapValues( this.subduxes = fp.mapValues(
@ -24,12 +37,11 @@ export class Updux {
this.actions = buildActions( this.actions = buildActions(
config.actions, config.actions,
config.mutations, [ ...Object.keys(config.mutations||{}), ...Object.keys(config.effects||{} ) ],
config.effects, fp.flatten( Object.values( this.subduxes ).map( ({actions}:Updux) => Object.entries(actions) ) ),
Object.values( this.subduxes ).map( ({actions}) => actions ),
) )
this.initial = buildInitial( this.initial = buildInitial<any>(
config.initial, fp.mapValues( ({initial}) => initial )(this.subduxes) config.initial, fp.mapValues( ({initial}) => initial )(this.subduxes)
); );
@ -42,16 +54,16 @@ export class Updux {
); );
this.reducer = (state,action) => { this.reducer = (state,action) => {
return this.upreducer(action)(state); return this.upreducer(action)(state as S);
} }
this.middleware = buildMiddleware( this.middleware = buildMiddleware(
config.effects, config.effects,
this.actions, 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);
} }
} }