Last active
September 3, 2019 22:18
-
-
Save krzysztof-miemiec/4b0d443fdca966bcd4a092409e9dd6cf to your computer and use it in GitHub Desktop.
TypeScript Redux Actions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type FunctionType = (...args: any[]) => any; | |
type ActionCreatorsMapObject = { [actionCreator: string]: FunctionType & { type?: string } }; | |
export type ActionsUnion<A extends ActionCreatorsMapObject> = ReturnType<A[keyof A]>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type ActionCreator<T, Payload> = { type: T } & ((...args: any[]) => { type: T } & Payload); | |
// No args | |
export function createAction<T extends string, Payload extends {}>( | |
type: T, creator?: () => Payload, | |
): { type: T } & (() => { type: T } & Payload); | |
// 1 arg, 1 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1>( | |
type: T, creator: (arg1?: Arg1) => Payload, | |
): { type: T } & ((arg1?: Arg1) => { type: T } & Payload); | |
// 1 arg | |
export function createAction<T extends string, Payload extends {}, Arg1>( | |
type: T, creator: (arg1: Arg1) => Payload, | |
): { type: T } & ((arg1: Arg1) => { type: T } & Payload); | |
// 2 args, 2 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2>( | |
type: T, creator: (arg1?: Arg1, arg2?: Arg2) => Payload, | |
): { type: T } & ((arg1?: Arg1, arg2?: Arg2) => { type: T } & Payload); | |
// 2 args, 1 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2>( | |
type: T, creator: (arg1: Arg1, arg2?: Arg2) => Payload, | |
): { type: T } & ((arg1: Arg1, arg2?: Arg2) => { type: T } & Payload); | |
// 2 args | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2>( | |
type: T, creator: (arg1: Arg1, arg2: Arg2) => Payload, | |
): { type: T } & ((arg1: Arg1, arg2: Arg2) => { type: T } & Payload); | |
// 3 args, 3 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2, Arg3>( | |
type: T, creator: (arg1?: Arg1, arg2?: Arg2, arg3?: Arg3) => Payload, | |
): { type: T } & ((arg1?: Arg1, arg2?: Arg2, arg3?: Arg3) => { type: T } & Payload); | |
// 3 args, 2 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2, Arg3>( | |
type: T, creator: (arg1: Arg1, arg2?: Arg2, arg3?: Arg3) => Payload, | |
): { type: T } & ((arg1: Arg1, arg2?: Arg2, arg3?: Arg3) => { type: T } & Payload); | |
// 3 args, 1 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2, Arg3>( | |
type: T, creator: (arg1: Arg1, arg2: Arg2, arg3?: Arg3) => Payload, | |
): { type: T } & ((arg1: Arg1, arg2: Arg2, arg3?: Arg3) => { type: T } & Payload); | |
// 3 args | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2, Arg3>( | |
type: T, creator: (arg1: Arg1, arg2: Arg2, arg3: Arg3) => Payload, | |
): { type: T } & ((arg1: Arg1, arg2: Arg2, arg3: Arg3) => { type: T } & Payload); | |
// 4 args, 4 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2, Arg3, Arg4>( | |
type: T, creator: (arg1?: Arg1, arg2?: Arg2, arg3?: Arg3, arg4?: Arg4) => Payload, | |
): { type: T } & ((arg1?: Arg1, arg2?: Arg2, arg3?: Arg3, arg4?: Arg4) => { type: T } & Payload); | |
// 4 args, 3 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2, Arg3, Arg4>( | |
type: T, creator: (arg1: Arg1, arg2?: Arg2, arg3?: Arg3, arg4?: Arg4) => Payload, | |
): { type: T } & ((arg1: Arg1, arg2?: Arg2, arg3?: Arg3, arg4?: Arg4) => { type: T } & Payload); | |
// 4 args, 2 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2, Arg3, Arg4>( | |
type: T, creator: (arg1: Arg1, arg2: Arg2, arg3?: Arg3, arg4?: Arg4) => Payload, | |
): { type: T } & ((arg1: Arg1, arg2: Arg2, arg3?: Arg3, arg4?: Arg4) => { type: T } & Payload); | |
// 4 args, 1 maybe | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2, Arg3, Arg4>( | |
type: T, creator: (arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4?: Arg4) => Payload, | |
): { type: T } & ((arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4?: Arg4) => { type: T } & Payload); | |
// 4 args | |
export function createAction<T extends string, Payload extends {}, Arg1, Arg2, Arg3, Arg4>( | |
type: T, creator: (arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4) => Payload, | |
): { type: T } & ((arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4) => { type: T } & Payload); | |
// Any args & basic definition | |
export function createAction<T extends string, Payload extends {}>( | |
type: T, actionPayloadCreator?: (...args: any[]) => Payload, | |
) { | |
const creator = (...args: any[]) => ({ | |
type, | |
...(actionPayloadCreator ? actionPayloadCreator(...args) as any : {}), | |
}); | |
creator.type = type; | |
return creator as ActionCreator<T, Payload>; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Omit } from 'react-redux'; | |
import { Action, AnyAction, Reducer } from 'redux'; | |
import { PersistConfig, persistReducer } from 'redux-persist'; | |
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2'; | |
import storage from 'redux-persist/lib/storage'; | |
import { createReducer } from './createReducer.util'; | |
const defaultPersistConfig = { | |
storage, | |
stateReconciler: autoMergeLevel2, | |
timeout: 2000, | |
}; | |
type PartialPersistConfig = Omit<PersistConfig, 'storage'>; | |
export const createPersistedReducer = <S extends object, A extends Action = AnyAction> | |
(reducer: Reducer<S, A>) => | |
(persistConfig: PartialPersistConfig): Reducer<S, A> => | |
persistReducer( | |
{ ...defaultPersistConfig, ...persistConfig }, | |
createReducer(reducer), | |
) as Reducer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Action, AnyAction, Reducer } from 'redux'; | |
export const createReducer = <S extends {}, A extends Action = AnyAction> | |
(reducer: Reducer<S, A>) => | |
(state: S | undefined, action: A): S => | |
action.type === AUTH_ACTIONS.CLEAR_STORAGE | |
? reducer(undefined, { ...(action as object), snapshot: state } as any) | |
: reducer(state, action); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Action } from 'redux'; | |
import { Observable } from 'rxjs'; | |
import { filter } from 'rxjs/operators'; | |
import { ActionCreator } from './createAction.util'; | |
// 3 action types | |
export function ofType<T extends string, Payload extends {}, | |
T2 extends string, Payload2 extends {}, | |
T3 extends string, Payload3 extends {}>( | |
creator1: ActionCreator<T, Payload>, | |
creator2: ActionCreator<T2, Payload2>, | |
creator3: ActionCreator<T3, Payload3>, | |
): (o: Observable<Action<any>>) => Observable<ReturnType<typeof creator1> | |
| ReturnType<typeof creator2> | |
| ReturnType<typeof creator3>>; | |
// 2 action types | |
export function ofType<T extends string, Payload extends {}, T2 extends string, Payload2 extends {}, InputT>( | |
creator1: ActionCreator<T, Payload>, | |
creator2: ActionCreator<T2, Payload2>, | |
): (o: Observable<Action<any>>) => Observable<ReturnType<typeof creator1>|ReturnType<typeof creator2>>; | |
// 1 action type | |
export function ofType<T extends string, Payload extends {}>( | |
creator: ActionCreator<T, Payload>, | |
): (o: Observable<Action<any>>) => Observable<ReturnType<typeof creator>>; | |
export function ofType(...actionCreators: Array<ActionCreator<string, any>>): (o: Observable<any>) => Observable<any> { | |
const types = actionCreators.map(creator => creator.type); | |
return filter(action => types.includes(action.type)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ActionsUnion, createAction } from '../../../utils'; | |
import { User } from './user.state'; | |
export enum USER_ACTIONS { | |
SET_PROFILE = '[User] SET_PROFILE', | |
} | |
export const UserActions = { | |
setProfile: createAction( | |
USER_ACTIONS.SET_PROFILE, | |
(profile: User) => ({ profile }), | |
), | |
}; | |
export type UserActions = ActionsUnion<typeof UserActions>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ActionsObservable, combineEpics } from 'redux-observable'; | |
import { of } from 'rxjs'; | |
import { mergeMap } from 'rxjs/operators'; | |
import { oftype } from 'ofType.operator.tsx'; | |
import { UserActions } from './user.actions'; | |
type Action$ = ActionsObservable<UserActions>; | |
export const setProfile$ = (action$: Action$) => action$.pipe( | |
ofType(UserActions.setProfile), | |
mergeMap(async ({ profile }) => { | |
// Do something... | |
return { type: '?' }; // Map result to another action | |
}), | |
); | |
export const epics = combineEpics<any>( | |
setProfile$, | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Sample reducer made using the utils | |
export const reducer = createPersistedReducer<UserState, UserActions>( | |
(state = initialState, action): UserState => { | |
switch (action.type) { | |
case USER_ACTIONS.SET_PROFILE: | |
return { | |
...state, | |
profile: defaultTo(state.profile)(action.profile), | |
}; | |
default: | |
return state; | |
} | |
}, | |
)({ | |
key: 'user', | |
blacklist: ['getUserQuery'], | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { PersistedState } from 'redux-persist'; | |
export const GET_USER_QUERY = 'getUserQuery'; | |
export interface User { | |
id: string; | |
firstName: string; | |
lastName: string; | |
email: string; | |
}; | |
export interface UserState extends PersistedState { | |
profile?: User; | |
getUserQuery: Query<User>; // Custom type for handling queries | |
} | |
export const initialState: UserState = { | |
profile: undefined, | |
getUserQuery: {}, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment