Skip to content

Commit

Permalink
Update dependencies
Browse files Browse the repository at this point in the history
- expose 'mapStoreToProps' function from store
- add 'mapDispatchToProps' functiion
  • Loading branch information
cimdalli committed Nov 13, 2019
1 parent aa74736 commit c9c7744
Show file tree
Hide file tree
Showing 12 changed files with 2,135 additions and 3,047 deletions.
460 changes: 289 additions & 171 deletions README.md

Large diffs are not rendered by default.

36 changes: 18 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,28 +50,28 @@
"redux": "^4.0.1"
},
"devDependencies": {
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.5",
"@types/react": "^16.7.18",
"@types/react-redux": "^6.0.11",
"@types/chai": "^4.2.4",
"@types/mocha": "^5.2.7",
"@types/react": "^16.9.11",
"@types/react-redux": "^7.1.5",
"chai": "^4.2.0",
"mocha": "^5.2.0",
"prettier-tslint": "^0.4.1",
"rimraf": "^2.6.2",
"source-map-support": "^0.5.9",
"ts-loader": "^5.3.2",
"ts-node": "^7.0.1",
"tslint-config-airbnb": "^5.11.1",
"typescript": "^3.2.2",
"webpack": "^4.28.2",
"webpack-cli": "^3.1.2",
"webpack-merge": "^4.1.5",
"mocha": "^6.2.2",
"prettier-tslint": "^0.4.2",
"rimraf": "^3.0.0",
"source-map-support": "^0.5.16",
"ts-loader": "^6.2.1",
"ts-node": "^8.5.0",
"tslint-config-airbnb": "^5.11.2",
"typescript": "^3.7.2",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-merge": "^4.2.2",
"webpack-node-externals": "^1.7.2"
},
"peerDependencies": {
"react": ">=15",
"react-dom": ">=15",
"react-redux": ">=5",
"react": ">=16",
"react-dom": ">=16",
"react-redux": ">=7",
"redux": ">=4"
},
"prettier": {
Expand Down
64 changes: 38 additions & 26 deletions src/helpers/redux.helpers.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
import { ActionCreatorDefinition, DispatchToProps, Indexer } from '..'

export const createAction = <TPayload = any, TMeta = any>(
type: string,
): ActionCreatorDefinition<TPayload, TMeta> => {
const creator: any = (payload?: TPayload, meta?: TMeta) => ({
payload,
meta,
type,
})
creator.type = type
return creator
}

export const mapDispatchToProps: DispatchToProps = map => (dispatch, own) => {
const mapper = <T extends Indexer>(m: T) =>
Object.keys(m).reduce(
(prev, key) => ({
...prev,
[key]: (...params: any[]) => dispatch(m[key](...params)),
}),
{},
) as typeof m

return typeof map === 'function' ? mapper(map(dispatch, own)) : mapper(map)
}
import { ActionCreatorDefinition, DispatchToProps, Indexer } from '..'

export const createAction = <TPayload = any, TMeta = any>(
type: string,
): ActionCreatorDefinition<TPayload, TMeta> => {
const creator: any = (payload?: TPayload, meta?: TMeta) => ({
payload,
meta,
type,
})
creator.type = type
return creator
}


/**
* Dummy function to return `MapDispatchToPropsParam` type that can be passed to `connect`
* As paramter, either mapper function which takes dispatch object and returns indexer object or indexer object is required
* ex.
* const changeLayout = createAction('changeLayout')
* const dispatchedProps = mapDispatchToProps((dispatch, own) => ({ changeLayout: () => dispatch(changeLayout()) }))
* // or
* const dispatchedProps = mapDispatchToProps({ changeLayout }))
*
* @param {*} map
*/
export const mapDispatchToProps: DispatchToProps = map => (dispatch, own) => {
const mapper = <T extends Indexer>(m: T) =>
Object.keys(m).reduce(
(prev, key) => ({
...prev,
[key]: (...params: any[]) => dispatch(m[key](...params)),
}),
{},
) as typeof m

return typeof map === 'function' ? mapper(map(dispatch, own)) : mapper(map)
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import './polyfills/promise.polyfill'

export * from './models/action.model'
export * from './models/redux.model'
export * from './reducer.builder'
Expand Down
41 changes: 19 additions & 22 deletions src/models/action.model.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import { Action as ReduxAction } from 'redux'

export interface Action<TPayload = any, TMeta = any>
extends ReduxAction<string> {
payload: TPayload
meta: TMeta
}

export interface ActionCreatorDefinition<TPayload, TMeta> {
(payload?: TPayload, meta?: TMeta): Action<TPayload, TMeta>
type: string
}

export type LazyDispatch = <TAction extends ReduxAction>(
action: TAction,
) => Promise<TAction>

export type ActionBody<TState, TPayload> = (
state: TState,
action: TPayload,
dispatch: LazyDispatch,
) => TState
import { Action as ReduxAction } from 'redux'

export interface Action<TPayload = any, TMeta = any> extends ReduxAction<string> {
payload: TPayload
meta: TMeta
}

export interface ActionCreatorDefinition<TPayload, TMeta> {
(payload?: TPayload, meta?: TMeta): Action<TPayload, TMeta>
type: string
}

export type LazyDispatch = <TAction extends ReduxAction>(action: TAction) => Promise<TAction>

export type ActionBody<TState, TPayload> = (
state: TState,
action: TPayload,
dispatch: LazyDispatch,
) => TState
32 changes: 16 additions & 16 deletions src/models/redux.model.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { AnyAction } from 'redux'
import { MapDispatchToPropsFunction, MapStateToProps } from 'react-redux'

export type Indexer<T = any> = { [key: string]: T }

export interface StateToProps<TState = any> {
<T extends Indexer, TOwn>(
map: MapStateToProps<T, TOwn, TState>,
): MapStateToProps<T, TOwn, TState>
}

export interface DispatchToProps {
<T extends Indexer<(...params: any[]) => AnyAction>, TOwn>(
map: T | MapDispatchToPropsFunction<T, TOwn>,
): MapDispatchToPropsFunction<T, TOwn>
}
import { MapDispatchToPropsFunction, MapStateToProps } from 'react-redux'
import { AnyAction } from 'redux'

export type Indexer<T = any> = { [key: string]: T }

export type StateToProps<TState = any> = {
<T extends Indexer, TOwn>(
map: MapStateToProps<T, TOwn, TState>,
): MapStateToProps<T, TOwn, TState>
}

export type DispatchToProps = {
<T extends Indexer<(...params: any[]) => AnyAction>, TOwn>(
map: T | MapDispatchToPropsFunction<T, TOwn>,
): MapDispatchToPropsFunction<T, TOwn>
}
34 changes: 17 additions & 17 deletions src/polyfills/promise.polyfill.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
interface PromiseConstructor {
defer<T>(): {
resolve: (value?: T | PromiseLike<T>) => void
reject: (reason?: any) => void
promise: Promise<T>,
}
}

Promise['defer'] = function deferPolyfill() {
const deferred = {} as any
const promise = new Promise((resolve, reject) => {
deferred.resolve = resolve
deferred.reject = reject
})
deferred.promise = promise
return deferred
}
interface PromiseConstructor {
defer<T>(): {
resolve: (value?: T | PromiseLike<T>) => void
reject: (reason?: any) => void
promise: Promise<T>,
}
}

Promise['defer'] = function deferPolyfill() {
const deferred = {} as any
const promise = new Promise((resolve, reject) => {
deferred.resolve = resolve
deferred.reject = reject
})
deferred.promise = promise
return deferred
}
101 changes: 51 additions & 50 deletions src/reducer.builder.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,51 @@
import { ActionBody, Action, ActionCreatorDefinition, LazyDispatch } from '.'
import { Dispatch, Reducer } from 'redux'

export class ReducerBuilder<State = {}> {
private actions: { [type: string]: ActionBody<State, Action> } = {}
private initState: State

/**
* Initial state of the reducer
*
* @param {State} state State object
* @returns
* @memberof ReducerBuilder
*/
public init(state: State) {
this.initState = state
return this
}

/**
* Consumer definition for given action type
*
* @template TPayload Action payload type
* @param {ActionCreatorDefinition<TPayload>} creator Action creator function
* @param {ActionBody<State, Action<TPayload>>} body Action body
* @returns
* @memberof ReducerBuilder
*/
public handle<TPayload, TMeta>(
creator: ActionCreatorDefinition<TPayload, TMeta>,
body: ActionBody<State, Action<TPayload, TMeta>>,
) {
this.actions[creator.type] = body
return this
}

private build(dispatchPromise: Promise<Dispatch>): Reducer<State, Action> {
return (state = this.initState, action) => {
const actionBody = this.actions[action.type]
const lazyDispatch: LazyDispatch = nestedAction =>
dispatchPromise.then(dispatch => dispatch(nestedAction))

if (!!actionBody) {
return actionBody(state, action, lazyDispatch)
}

return state
}
}
}
import { Dispatch, Reducer } from 'redux'

import { Action, ActionBody, ActionCreatorDefinition, LazyDispatch } from '.'

export class ReducerBuilder<State = {}> {
private actions: { [type: string]: ActionBody<State, Action> } = {}
private initState: State

/**
* Initial state of the reducer
*
* @param {State} state State object
* @returns
* @memberof ReducerBuilder
*/
public init(state: State) {
this.initState = state
return this
}

/**
* Consumer definition for given action type
*
* @template TPayload Action payload type
* @param {ActionCreatorDefinition<TPayload>} creator Action creator function
* @param {ActionBody<State, Action<TPayload>>} body Action body
* @returns
* @memberof ReducerBuilder
*/
public handle<TPayload, TMeta>(
creator: ActionCreatorDefinition<TPayload, TMeta>,
body: ActionBody<State, Action<TPayload, TMeta>>,
) {
this.actions[creator.type] = body
return this
}

private build(dispatchPromise: Promise<Dispatch>): Reducer<State, Action> {
return (state = this.initState, action) => {
const actionBody = this.actions[action.type]
const lazyDispatch: LazyDispatch = nestedAction =>
dispatchPromise.then(dispatch => dispatch(nestedAction))

if (!!actionBody) {
return actionBody(state, action, lazyDispatch)
}

return state
}
}
}
Loading

0 comments on commit c9c7744

Please sign in to comment.