Tweaks to flow types
This commit is contained in:
parent
69a0d3c616
commit
00087c751d
60
src/index.js
60
src/index.js
|
@ -1,5 +1,5 @@
|
||||||
import { buildReducers } from './redux-arg/buildReducers';
|
import { buildReducers } from './redux-arg/buildReducers';
|
||||||
import { createStore, compose } from 'redux';
|
import { createStore, compose, combineReducers } from 'redux';
|
||||||
import { Types } from './redux-arg/structure';
|
import { Types } from './redux-arg/structure';
|
||||||
|
|
||||||
const exampleReducer = {
|
const exampleReducer = {
|
||||||
|
@ -30,26 +30,62 @@ const exampleReducer = {
|
||||||
arrayTest: Types.reducer(Types.arrayOf(
|
arrayTest: Types.reducer(Types.arrayOf(
|
||||||
Types.number(),
|
Types.number(),
|
||||||
[1,3,4]
|
[1,3,4]
|
||||||
))
|
)),
|
||||||
|
primitiveTest: Types.reducer(Types.number(4)),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const exampleReducer2 = {
|
||||||
|
screen: Types.reducer(Types.shape({
|
||||||
|
handlerIsCBS: Types.boolean(true),
|
||||||
|
handlerIsENG: Types.boolean(true),
|
||||||
|
invoices: Types.arrayOf(Types.string()),
|
||||||
|
activeInvoice: Types.number(-1),
|
||||||
|
deleteInvoiceModalActive: Types.boolean(),
|
||||||
|
suppInvoiceModalActive: Types.boolean(),
|
||||||
|
paymentModalActive: Types.boolean(),
|
||||||
|
resetModalActive: Types.boolean(),
|
||||||
|
reinstateModalActive: Types.boolean(),
|
||||||
|
})),
|
||||||
|
delete: Types.reducer(Types.shape({
|
||||||
|
invoiceSequence: Types.number(),
|
||||||
|
vehicleSequence: Types.number(),
|
||||||
|
deleteReason: Types.string(),
|
||||||
|
})),
|
||||||
|
supp: Types.reducer(Types.shape({
|
||||||
|
invoiceSequence: Types.number(),
|
||||||
|
vehicleSequence: Types.number(),
|
||||||
|
mode: Types.string(),
|
||||||
|
amount: Types.string(),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
const test = buildReducers('example', exampleReducer);
|
const test = buildReducers('example', exampleReducer);
|
||||||
|
const test2 = buildReducers('invoices', exampleReducer2);
|
||||||
|
|
||||||
const store = createStore(
|
const store = createStore(
|
||||||
test.reducers,
|
combineReducers({
|
||||||
|
example: test.reducers,
|
||||||
|
invoices: test2.reducers,
|
||||||
|
}),
|
||||||
compose(window.devToolsExtension ? window.devToolsExtension() : f => f)
|
compose(window.devToolsExtension ? window.devToolsExtension() : f => f)
|
||||||
);
|
);
|
||||||
|
|
||||||
store.dispatch(test.actionsObject.example.form2.update({ lowerLevel: 2, lowerLevel2: 'Rawrg', lowerLevelArray: [3, 'foo'] }));
|
store.dispatch(test.actions.example.form2.update({ lowerLevel: 2, lowerLevel2: 'Rawrg', lowerLevelArray: [3, 'foo'] }));
|
||||||
store.dispatch(test.actionsObject.example.form2.reset());
|
store.dispatch(test.actions.example.form2.reset());
|
||||||
store.dispatch(test.actionsObject.example.form2.replace({ toast: 'nommyNom' }));
|
store.dispatch(test.actions.example.form2.replace({ toast: 'nommyNom' }));
|
||||||
store.dispatch(test.actionsObject.example.form2.reset());
|
store.dispatch(test.actions.example.form2.reset());
|
||||||
|
|
||||||
console.log(111, test.selectorsObject.example.form2(store.getState()));
|
console.log(111, test.selectors.example.form2(store.getState()));
|
||||||
console.log(222, test.actionsObject);
|
console.log(222, test.actions);
|
||||||
|
console.log(333, test.selectors);
|
||||||
|
console.log(444, test.selectors.example.primitiveTest(store.getState()));
|
||||||
|
console.log(555, test2.selectors, test2.actions);
|
||||||
|
console.log(666, test2.selectors.screen(store.getState()));
|
||||||
|
|
||||||
store.dispatch(test.actionsObject.example.arrayTest.replace([1,2,3]));
|
store.dispatch(test.actions.example.arrayTest.replace([1,2,3]));
|
||||||
store.dispatch(test.actionsObject.example.arrayTest.updateAtIndex(5, 0));
|
store.dispatch(test.actions.example.arrayTest.updateAtIndex(5, 0));
|
||||||
store.dispatch(test.actionsObject.example.arrayTest.updateAtIndex('foo', 0));
|
store.dispatch(test.actions.example.arrayTest.updateAtIndex('foo', 0));
|
||||||
|
|
||||||
|
store.dispatch(test.actions.example.primitiveTest.update(5));
|
||||||
|
store.dispatch(test.actions.example.primitiveTest.reset());
|
||||||
|
|
|
@ -10,8 +10,9 @@ import { reduce, find } from 'lodash';
|
||||||
import { createReducer } from './reducers';
|
import { createReducer } from './reducers';
|
||||||
import { PROP_TYPES } from './structure';
|
import { PROP_TYPES } from './structure';
|
||||||
|
|
||||||
|
|
||||||
export function buildReducers(name: string, structure: any, {
|
export function buildReducers(name: string, structure: any, {
|
||||||
baseSelector = state => state,
|
baseSelector = state => state[name],
|
||||||
locationString = '',
|
locationString = '',
|
||||||
}: {
|
}: {
|
||||||
baseSelector: any,
|
baseSelector: any,
|
||||||
|
@ -24,8 +25,8 @@ export function buildReducers(name: string, structure: any, {
|
||||||
//returned to the call site for use in the rest of the application.
|
//returned to the call site for use in the rest of the application.
|
||||||
const temp = reduce(structure, processStructure, {
|
const temp = reduce(structure, processStructure, {
|
||||||
reducers: {},
|
reducers: {},
|
||||||
actionsObject: {},
|
actions: {},
|
||||||
selectorsObject: {},
|
selectors: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
//The Redux 'combineReducers' helper function is used here to save a little bit of boilerplate.
|
//The Redux 'combineReducers' helper function is used here to save a little bit of boilerplate.
|
||||||
|
@ -63,13 +64,13 @@ export function buildReducers(name: string, structure: any, {
|
||||||
...memo.reducers,
|
...memo.reducers,
|
||||||
[propName]: childReducer.reducers,
|
[propName]: childReducer.reducers,
|
||||||
},
|
},
|
||||||
actionsObject: {
|
actions: {
|
||||||
...memo.actionsObject,
|
...memo.actions,
|
||||||
[propName]: childReducer.actionsObject,
|
[propName]: childReducer.actions,
|
||||||
},
|
},
|
||||||
selectorsObject: {
|
selectors: {
|
||||||
...memo.selectorsObject,
|
...memo.selectors,
|
||||||
[propName]: containsReducers ? childReducer.selectorsObject : state => baseSelector(state)[propName],
|
[propName]: containsReducers ? childReducer.selectors : state => baseSelector(state)[propName],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,12 @@ import type {
|
||||||
//==============================
|
//==============================
|
||||||
export type PartialReducer = {
|
export type PartialReducer = {
|
||||||
reducers: { [key: string]: any },
|
reducers: { [key: string]: any },
|
||||||
actionsObject: { [key: string]: any },
|
actions: { [key: string]: any },
|
||||||
selectorsObject?: { [key: string]: any },
|
selectors: { [key: string]: any },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Selector = (state: Object) => any;
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PROP_TYPES,
|
PROP_TYPES,
|
||||||
} from './structure';
|
} from './structure';
|
||||||
|
@ -23,6 +25,7 @@ import { compose } from 'ramda';
|
||||||
import { reduce } from 'lodash';
|
import { reduce } from 'lodash';
|
||||||
import { createObjectReducer } from './reducers/objectReducer';
|
import { createObjectReducer } from './reducers/objectReducer';
|
||||||
import { createArrayReducer } from './reducers/arrayReducer';
|
import { createArrayReducer } from './reducers/arrayReducer';
|
||||||
|
import { createPrimitiveReducer } from './reducers/primitiveReducer';
|
||||||
|
|
||||||
|
|
||||||
function determineReducerType(reducerDescriptor, {
|
function determineReducerType(reducerDescriptor, {
|
||||||
|
@ -31,9 +34,9 @@ function determineReducerType(reducerDescriptor, {
|
||||||
const REDUCERS = {
|
const REDUCERS = {
|
||||||
[PROP_TYPES._shape]: createObjectReducer,
|
[PROP_TYPES._shape]: createObjectReducer,
|
||||||
[PROP_TYPES._array]: createArrayReducer,
|
[PROP_TYPES._array]: createArrayReducer,
|
||||||
[PROP_TYPES._boolean]: () => {},
|
[PROP_TYPES._boolean]: createPrimitiveReducer,
|
||||||
[PROP_TYPES._string]: () => {},
|
[PROP_TYPES._string]: createPrimitiveReducer,
|
||||||
[PROP_TYPES._number]: () => {},
|
[PROP_TYPES._number]: createPrimitiveReducer,
|
||||||
};
|
};
|
||||||
const { structure } = reducerDescriptor();
|
const { structure } = reducerDescriptor();
|
||||||
const { type } = structure();
|
const { type } = structure();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//==============================
|
//==============================
|
||||||
// Flow imports
|
// Flow imports
|
||||||
//==============================
|
//==============================
|
||||||
import type { StructureType, ArrayStructureType } from '../structure';
|
import type { ArrayStructureType } from '../structure';
|
||||||
|
|
||||||
//==============================
|
//==============================
|
||||||
// Flow types
|
// Flow types
|
||||||
|
@ -100,7 +100,7 @@ export function createArrayReducer(arrayTypeDescription: ArrayStructureType, {
|
||||||
}: ArrayReducerOptions = {}) {
|
}: ArrayReducerOptions = {}) {
|
||||||
return {
|
return {
|
||||||
reducers: createReducer(arrayTypeDescription, createReducerBehaviors(DEFAULT_ARRAY_BEHAVIORS, locationString)),
|
reducers: createReducer(arrayTypeDescription, createReducerBehaviors(DEFAULT_ARRAY_BEHAVIORS, locationString)),
|
||||||
actionsObject: createActions(DEFAULT_ARRAY_BEHAVIORS, locationString, {}),
|
actions: createActions(DEFAULT_ARRAY_BEHAVIORS, locationString, {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ function createActions(behaviorsConfig: ArrayReducerBehaviorsConfig, locationStr
|
||||||
...memo,
|
...memo,
|
||||||
[name]: (value: Array<any>, index: ?number) => ({
|
[name]: (value: Array<any>, index: ?number) => ({
|
||||||
type: `${locationString}.${name}`,
|
type: `${locationString}.${name}`,
|
||||||
payload: (behavior.action || (() => value))(value) || [],
|
payload: (behavior.action || (() => value))(value),
|
||||||
index,
|
index,
|
||||||
})
|
})
|
||||||
}), {});
|
}), {});
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//==============================
|
//==============================
|
||||||
// Flow imports
|
// Flow imports
|
||||||
//==============================
|
//==============================
|
||||||
import type { ShapeStructure, StructureType } from '../structure';
|
import type { StructureType } from '../structure';
|
||||||
|
|
||||||
//==============================
|
//==============================
|
||||||
// Flow types
|
// Flow types
|
||||||
|
@ -11,7 +11,6 @@ export type ObjectReducerAction = {
|
||||||
type: string,
|
type: string,
|
||||||
payload: Object,
|
payload: Object,
|
||||||
};
|
};
|
||||||
export type ObjectReducerFactory = (reducerStructure: ShapeStructure) => ObjectReducer;
|
|
||||||
export type ObjectReducer = (state: Object, action: ObjectReducerAction) => Object;
|
export type ObjectReducer = (state: Object, action: ObjectReducerAction) => Object;
|
||||||
export type ObjectReducerBehavior = (state: Object, payload: Object | void, initialState: Object) => Object;
|
export type ObjectReducerBehavior = (state: Object, payload: Object | void, initialState: Object) => Object;
|
||||||
export type ObjectReducerBehaviorsConfig = {
|
export type ObjectReducerBehaviorsConfig = {
|
||||||
|
@ -31,7 +30,6 @@ export type ObjectReducerOptions = {
|
||||||
behaviorsConfig: ObjectReducerBehaviorsConfig,
|
behaviorsConfig: ObjectReducerBehaviorsConfig,
|
||||||
locationString: string,
|
locationString: string,
|
||||||
};
|
};
|
||||||
export type ObjectSelector = (state: Object) => Object;
|
|
||||||
|
|
||||||
//==============================
|
//==============================
|
||||||
// JS imports
|
// JS imports
|
||||||
|
@ -66,7 +64,7 @@ export function createObjectReducer(reducerShape: StructureType, {
|
||||||
}: ObjectReducerOptions = {}) {
|
}: ObjectReducerOptions = {}) {
|
||||||
return {
|
return {
|
||||||
reducers: createReducer(reducerShape, createReducerBehaviors(DEFAULT_OBJECT_BEHAVIORS, locationString)),
|
reducers: createReducer(reducerShape, createReducerBehaviors(DEFAULT_OBJECT_BEHAVIORS, locationString)),
|
||||||
actionsObject: createActions(DEFAULT_OBJECT_BEHAVIORS, locationString, {}),
|
actions: createActions(DEFAULT_OBJECT_BEHAVIORS, locationString, {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +98,7 @@ function createActions(behaviorsConfig: ObjectReducerBehaviorsConfig, locationSt
|
||||||
...memo,
|
...memo,
|
||||||
[name]: (value: Object) => ({
|
[name]: (value: Object) => ({
|
||||||
type: `${locationString}.${name}`,
|
type: `${locationString}.${name}`,
|
||||||
payload: (behavior.action || (() => defaultPayload))(value) || {}
|
payload: (behavior.action || (() => defaultPayload))(value),
|
||||||
})
|
})
|
||||||
}), {});
|
}), {});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,92 @@
|
||||||
|
//@flow
|
||||||
|
//==============================
|
||||||
|
// Flow imports
|
||||||
|
//==============================
|
||||||
|
import type { PrimitiveType } from '../structure';
|
||||||
|
|
||||||
|
//==============================
|
||||||
|
// Flow types
|
||||||
|
//==============================
|
||||||
|
export type PrimitiveReducerAction = {
|
||||||
|
type: string,
|
||||||
|
payload: mixed,
|
||||||
|
};
|
||||||
|
export type PrimitiveReducer = (state: mixed, action: PrimitiveReducerAction) => mixed;
|
||||||
|
export type PrimitiveReducerBehavior = (state: mixed, payload: mixed | void, initialState: mixed) => mixed;
|
||||||
|
export type PrimitiveReducerBehaviorsConfig = {
|
||||||
|
[key: string]: {
|
||||||
|
action?: (value: mixed) => mixed,
|
||||||
|
reducer: PrimitiveReducerBehavior,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export type PrimitiveReducerBehaviors = {
|
||||||
|
[key: string]: PrimitiveReducerBehavior,
|
||||||
|
};
|
||||||
|
export type PrimitiveAction = (value: mixed) => { type: string, payload: mixed };
|
||||||
|
export type PrimitiveActions = {
|
||||||
|
[key: string]: PrimitiveAction
|
||||||
|
};
|
||||||
|
export type PrimitiveReducerOptions = {
|
||||||
|
behaviorsConfig: PrimitiveReducerBehaviorsConfig,
|
||||||
|
locationString: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================
|
||||||
|
// JS imports
|
||||||
|
//==============================
|
||||||
|
import { reduce } from 'lodash';
|
||||||
|
import { validatePrimitive } from '../validatePayload';
|
||||||
|
import { createReducerBehaviors } from '../reducers';
|
||||||
|
|
||||||
|
const DEFAULT_PRIMITIVE_BEHAVIORS: PrimitiveReducerBehaviorsConfig = {
|
||||||
|
update: {
|
||||||
|
action(value) { return value },
|
||||||
|
reducer(state, payload) {
|
||||||
|
if (payload === undefined) return state;
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reset: {
|
||||||
|
reducer(state, payload, initialState) {
|
||||||
|
return initialState;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export function createPrimitiveReducer(primitiveType: PrimitiveType, {
|
||||||
|
locationString
|
||||||
|
}: PrimitiveReducerOptions = {}) {
|
||||||
|
return {
|
||||||
|
reducers: createReducer(primitiveType, createReducerBehaviors(DEFAULT_PRIMITIVE_BEHAVIORS, locationString)),
|
||||||
|
actions: createActions(DEFAULT_PRIMITIVE_BEHAVIORS, locationString, {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createReducer(primitiveType: PrimitiveType, behaviors: PrimitiveReducerBehaviors): PrimitiveReducer {
|
||||||
|
const initialState: mixed = validatePrimitive(primitiveType, primitiveType().defaultValue);
|
||||||
|
return (state = initialState, { type, payload }: PrimitiveReducerAction) => {
|
||||||
|
//If the action type does not match any of the specified behaviors, just return the current state.
|
||||||
|
if (!behaviors[type]) return state;
|
||||||
|
|
||||||
|
//Sanitize the payload using the reducer shape, then apply the sanitized
|
||||||
|
//payload to the state using the behavior linked to this action type.
|
||||||
|
return behaviors[type](state, validatePrimitive(primitiveType, payload), initialState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createActions(behaviorsConfig: PrimitiveReducerBehaviorsConfig, locationString: string, defaultPayload: any): PrimitiveActions {
|
||||||
|
//Take a reducer behavior config object, and create actions using the location string
|
||||||
|
return reduce(behaviorsConfig, (memo, behavior, name) => ({
|
||||||
|
...memo,
|
||||||
|
[name]: (value: mixed) => ({
|
||||||
|
type: `${locationString}.${name}`,
|
||||||
|
payload: (behavior.action || (() => defaultPayload))(value),
|
||||||
|
})
|
||||||
|
}), {});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// Flow types
|
// Flow types
|
||||||
//==============================
|
//==============================
|
||||||
export type ShapeStructure = {
|
export type ShapeStructure = {
|
||||||
[key: string]: StructureType | PrimitiveType,
|
[key: string]: StructureType | PrimitiveType | ArrayStructureType,
|
||||||
}
|
}
|
||||||
export type StructureType = () => {
|
export type StructureType = () => {
|
||||||
type: string,
|
type: string,
|
||||||
|
|
Loading…
Reference in New Issue