@housinganywhere/safe-redux
Advanced tools
Comparing version 1.1.1 to 1.2.0
@@ -13,8 +13,9 @@ "use strict"; | ||
exports.createAction = createAction; | ||
function handleActions(handler, initialState) { | ||
function handleActions(handlers, initialState) { | ||
return function (state, action) { | ||
if (state === void 0) { state = initialState; } | ||
return handler[action.type] ? handler[action.type](state, action) : state; | ||
var handler = handlers[action.type]; | ||
return handler ? handler(state, action) : state; | ||
}; | ||
} | ||
exports.handleActions = handleActions; |
@@ -10,7 +10,8 @@ export function createAction(type, payload, meta) { | ||
} | ||
export function handleActions(handler, initialState) { | ||
export function handleActions(handlers, initialState) { | ||
return function (state, action) { | ||
if (state === void 0) { state = initialState; } | ||
return handler[action.type] ? handler[action.type](state, action) : state; | ||
var handler = handlers[action.type]; | ||
return handler ? handler(state, action) : state; | ||
}; | ||
} |
@@ -22,6 +22,7 @@ (function (factory) { | ||
exports.createAction = createAction; | ||
function handleActions(handler, initialState) { | ||
function handleActions(handlers, initialState) { | ||
return function (state, action) { | ||
if (state === void 0) { state = initialState; } | ||
return handler[action.type] ? handler[action.type](state, action) : state; | ||
var handler = handlers[action.type]; | ||
return handler ? handler(state, action) : state; | ||
}; | ||
@@ -28,0 +29,0 @@ } |
{ | ||
"name": "@housinganywhere/safe-redux", | ||
"version": "1.1.1", | ||
"version": "1.2.0", | ||
"description": "Create and handle safely typed actions", | ||
@@ -5,0 +5,0 @@ "main": "./dist/cmjs/index.js", |
@@ -58,3 +58,3 @@ # safe-redux :evergreen_tree: | ||
import { handleActions } from '@housinganywhere/safe-redux'; | ||
import { handleActions, Handler } from '@housinganywhere/safe-redux'; | ||
@@ -73,2 +73,8 @@ import { User } from '../types'; | ||
// `Handler` type can be used when you don't want to define the handlers inline | ||
const handleIncBy: Handler<State, typeof INC_BY, Actions> = ( | ||
{ count }, | ||
{ payload }, | ||
) => ({ count: count + payload }); | ||
const reducer = handleActions<State, ActionTypes, Actions>( | ||
@@ -78,3 +84,3 @@ { | ||
[DEC]: ({ count }) => ({ count: count - 1 }), | ||
[INC_BY]: ({ count }, { payload }) => ({ count: count + payload }), | ||
[INC_BY]: handleIncBy, | ||
[WITH_META]: ({ count }, { payload }) => ({ count: count + payload }), | ||
@@ -146,2 +152,3 @@ }, | ||
- Functions: `createAction` and `handleActions`. | ||
- Types: `Action`, `ActionsUnion`, `ActionsOfType` and `BindAction`. | ||
- Types: `Action`, `ActionsUnion`, `ActionsOfType`, `Handler` and | ||
`BindAction`. |
@@ -1,2 +0,2 @@ | ||
import { createAction, handleActions } from './index'; | ||
import { createAction, handleActions, ActionsUnion, Handler } from './index'; | ||
@@ -15,4 +15,4 @@ describe('handleActions', () => { | ||
it('should handle actions', () => { | ||
const action = { type: ACTION }; | ||
it('handles actions', () => { | ||
const action = { type: ACTION, error: false }; | ||
@@ -25,5 +25,5 @@ const actual = reducer(initialState, action); | ||
it('should return state when action type is not handled', () => { | ||
const action = { type: 'other_action' }; | ||
const state = { foo: 'foo' }; | ||
it('returns state when action type is not handled', () => { | ||
const action = { type: 'other_action', error: false }; | ||
const state = { foo: 'foo', error: false }; | ||
@@ -35,4 +35,4 @@ const actual = reducer(state, action); | ||
it('should default to initialState when state is undefined', () => { | ||
const action = { type: ACTION }; | ||
it('defaults to initialState when state is undefined', () => { | ||
const action = { type: ACTION, error: false }; | ||
@@ -44,4 +44,4 @@ reducer(undefined, action); | ||
it('should return initialState when state is undefined and action is not handled', () => { | ||
const actual = reducer(undefined, { type: '@@REDUX/INIT' }); | ||
it('returns initialState when state is undefined and action is not handled', () => { | ||
const actual = reducer(undefined, { type: '@@REDUX/INIT', error: false }); | ||
@@ -53,3 +53,3 @@ expect(actual).toBe(initialState); | ||
describe('createAction', () => { | ||
it('should create an action with only type and error props', () => { | ||
it('creates an action with only type and error props', () => { | ||
const action = createAction('action-type'); | ||
@@ -60,3 +60,3 @@ | ||
it('should create an action false error prop', () => { | ||
it('creates an action false error prop', () => { | ||
const action = createAction('action-type'); | ||
@@ -67,3 +67,3 @@ | ||
it('should create an action with type, payload and error props', () => { | ||
it('creates an action with type, payload and error props', () => { | ||
const payload = { foo: 'bar' }; | ||
@@ -75,3 +75,3 @@ const action = createAction('action-type', payload); | ||
it('should create an action true error prop', () => { | ||
it('creates an action true error prop', () => { | ||
const payload = new Error('error'); | ||
@@ -84,3 +84,3 @@ const action = createAction('action-type', payload); | ||
it('should create an action with type, payload, meta and error props', () => { | ||
it('creates an action with type, payload, meta and error props', () => { | ||
const payload = { foo: 'bar' }; | ||
@@ -98,3 +98,3 @@ const meta = { foo: 'bar' }; | ||
it('should create an action true error prop and meta', () => { | ||
it('creates an action true error prop and meta', () => { | ||
const payload = new Error('error'); | ||
@@ -113,1 +113,34 @@ const meta = { foo: 'bar' }; | ||
}); | ||
// type tests, all these should type check | ||
interface State { | ||
foo: string; | ||
} | ||
const enum ActionTypes { | ||
foo = 'foo', | ||
bar = 'bar', | ||
baz = 'baz', | ||
} | ||
const Actions = { | ||
foo: () => createAction(ActionTypes.foo), | ||
bar: (s: string) => createAction(ActionTypes.bar, s), | ||
baz: (n: number) => createAction(ActionTypes.baz, n), | ||
}; | ||
type Actions = ActionsUnion<typeof Actions>; | ||
const handleBaz: Handler<State, ActionTypes.baz, Actions> = ( | ||
s, | ||
{ payload }, | ||
) => ({ foo: s.foo + payload.toString() }); | ||
const reducer = handleActions<State, ActionTypes, Actions>( | ||
{ | ||
foo: () => ({ foo: 'foo' }), | ||
bar: (s, { payload }) => ({ foo: s.foo + payload }), | ||
baz: handleBaz, | ||
}, | ||
{ foo: 'bar' }, | ||
); |
export { BindAction } from './utils'; | ||
import { AnyFunction, StringMap } from './utils'; | ||
import { ReturnType } from './utils'; | ||
@@ -17,6 +17,7 @@ // We use conditional types so we can have only one type for defining Action | ||
export type ActionsUnion<A extends StringMap<AnyFunction>> = ReturnType< | ||
A[keyof A] | ||
>; | ||
type ActionCreator = (...args: any[]) => Action; | ||
type ActionCreators = { [k: string]: ActionCreator }; | ||
export type ActionsUnion<A extends ActionCreators> = ReturnType<A[keyof A]>; | ||
// conditional type for filtering actions in epics/effects | ||
@@ -28,2 +29,7 @@ export type ActionsOfType< | ||
export type Handler<State, ActionType extends string, Actions> = ( | ||
state: State, | ||
action: ActionsOfType<Actions, ActionType>, | ||
) => State; | ||
export function createAction<T extends string>(type: T): Action<T>; | ||
@@ -56,11 +62,9 @@ export function createAction<T extends string, P>( | ||
Types extends string, | ||
Actions extends ActionsUnion<{ [T in Types]: AnyFunction }> | ||
>( | ||
handler: { | ||
[T in Types]: (state: State, action: ActionsOfType<Actions, T>) => State; | ||
}, | ||
initialState: State, | ||
) { | ||
return (state = initialState, action: Actions): State => | ||
handler[action.type] ? handler[action.type](state, action) : state; | ||
Actions extends ActionsUnion<{ [T in Types]: ActionCreator }> | ||
>(handlers: { [T in Types]: Handler<State, T, Actions> }, initialState: State) { | ||
return (state = initialState, action: Actions): State => { | ||
const handler = handlers[action.type]; | ||
return handler ? handler(state, action) : state; | ||
}; | ||
} |
@@ -88,3 +88,8 @@ // tslint:disable no-any | ||
export type AnyFunction = (...args: any[]) => any; | ||
// TS `ReturnType` defaults to `any` instead of `never` | ||
export type ReturnType<T extends (...args: any[]) => any> = T extends ( | ||
...args: any[] | ||
) => infer R | ||
? R | ||
: never; | ||
@@ -96,5 +101,1 @@ // tslint:enable no-any | ||
export type BindAction<A> = ChangeReturnType<A, void>; | ||
export interface StringMap<T> { | ||
[key: string]: T; | ||
} |
export { BindAction } from './utils'; | ||
import { AnyFunction, StringMap } from './utils'; | ||
import { ReturnType } from './utils'; | ||
export declare type Action<T extends string = string, P = void, M = void> = P extends void ? M extends void ? Readonly<{ | ||
@@ -20,4 +20,9 @@ type: T; | ||
}>; | ||
export declare type ActionsUnion<A extends StringMap<AnyFunction>> = ReturnType<A[keyof A]>; | ||
declare type ActionCreator = (...args: any[]) => Action; | ||
declare type ActionCreators = { | ||
[k: string]: ActionCreator; | ||
}; | ||
export declare type ActionsUnion<A extends ActionCreators> = ReturnType<A[keyof A]>; | ||
export declare type ActionsOfType<ActionUnion, ActionType extends string> = ActionUnion extends Action<ActionType> ? ActionUnion : never; | ||
export declare type Handler<State, ActionType extends string, Actions> = (state: State, action: ActionsOfType<Actions, ActionType>) => State; | ||
export declare function createAction<T extends string>(type: T): Action<T>; | ||
@@ -27,5 +32,5 @@ export declare function createAction<T extends string, P>(type: T, payload: P): Action<T, P>; | ||
export declare function handleActions<State, Types extends string, Actions extends ActionsUnion<{ | ||
[T in Types]: AnyFunction; | ||
}>>(handler: { | ||
[T in Types]: (state: State, action: ActionsOfType<Actions, T>) => State; | ||
[T in Types]: ActionCreator; | ||
}>>(handlers: { | ||
[T in Types]: Handler<State, T, Actions>; | ||
}, initialState: State): (state: State | undefined, action: Actions) => State; |
declare type ChangeReturnType<F, R> = F extends () => any ? () => R : F extends (arg: infer A) => any ? (arg: A) => R : F extends (arg1: infer A, arg2: infer B) => any ? (arg1: A, arg2: B) => R : F extends (arg1: infer A, arg2: infer B, arg3: infer C) => any ? (arg1: A, arg2: B, arg3: C) => R : F extends (arg1: infer A, arg2: infer B, arg3: infer C, arg4: infer D) => any ? (arg1: A, arg2: B, arg3: C, arg4: D) => R : F extends (arg1: infer A, arg2: infer B, arg3: infer C, arg4: infer D, arg5: infer E) => any ? (arg1: A, arg2: B, arg3: C, arg4: E, arg5: D) => R : F extends (arg1: infer A, arg2: infer B, arg3: infer C, arg4: infer D, arg5: infer E, arg6: infer F) => any ? (arg1: A, arg2: B, arg3: C, arg4: D, arg5: E, arg6: F) => R : F extends (arg1: infer A, arg2: infer B, arg3: infer C, arg4: infer D, arg5: infer E, arg6: infer F, arg7: infer G) => any ? (arg1: A, arg2: B, arg3: C, arg4: D, arg5: E, arg6: F, arg7: G) => R : F extends (arg1: infer A, arg2: infer B, arg3: infer C, arg4: infer D, arg5: infer E, arg6: infer F, arg7: infer G, arg8: infer H) => any ? (arg1: A, arg2: B, arg3: C, arg4: D, arg5: E, arg6: F, arg7: G, arg8: H) => R : F extends (arg1: infer A, arg2: infer B, arg3: infer C, arg4: infer D, arg5: infer E, arg6: infer F, arg7: infer G, arg8: infer H, arg9: infer I) => any ? (arg1: A, arg2: B, arg3: C, arg4: D, arg5: E, arg6: F, arg7: G, arg8: H, arg9: I) => R : never; | ||
export declare type AnyFunction = (...args: any[]) => any; | ||
export declare type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : never; | ||
export declare type BindAction<A> = ChangeReturnType<A, void>; | ||
export interface StringMap<T> { | ||
[key: string]: T; | ||
} | ||
export {}; |
22358
407
151