Created
September 21, 2020 12:30
-
-
Save jantimon/f4072993432327c7a850d9ff592b397e to your computer and use it in GitHub Desktop.
use reducer typings
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 const actionCreator = <TState>() => <TOptions extends {}>( | |
actionHandler: ActionHandler<TOptions, TState> | |
) => actionHandler; | |
type ActionHandler<TOptions extends {}, TState extends {}> = ( | |
state: TState, | |
options: TOptions | |
) => TState; | |
type ActionOptions<T> = T extends ActionHandler<infer TOptions, infer State> | |
? TOptions | |
: never; | |
type ActionState<T> = T extends ActionHandler<infer TOptions, infer TState> | |
? TState | |
: never; | |
type ActionMapper<T extends { [key: string]: ActionHandler<any, any> }> = { | |
readonly [P in keyof T]: { | |
type: P; | |
value: ActionOptions<T[P]>; | |
}; | |
}; | |
type ValueOf<T> = T[keyof T]; | |
export type ActionTypes< | |
T extends { [key: string]: ActionHandler<any, any> } | |
> = ValueOf<ActionMapper<T>>; | |
export const createReducer = <T extends { [key: string]: ActionHandler<any, any> }> (actions: T) => { | |
type State = ActionState<ValueOf<T>>; | |
return (state: State, action: ActionTypes<T>) => actions[action.type](state, action.value); | |
} | |
export type ReducerDispatcher<T extends (state: any, action: any) => any> = T extends (state: any, action: infer TAction) => any ? React.Dispatch<TAction> : never |
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 { actionCreator, createReducer, ReducerDispatcher } from "./reducerTypings"; | |
export interface NavigationStore { | |
/** | |
* Breadcrumb of all open Navigation level | |
* | |
* for example if the navigation is entirely close: | |
* `false` | |
* | |
* for example if only the root level is open: | |
* | |
* [{ href: '/', title: 'Home', items: [...]}] | |
* | |
* for example if only a child of the root level is open: | |
* | |
* [{ href: '/about', title: 'About us', items: [...]}, { href: '/', title: 'Home', items: [...]}] | |
* | |
*/ | |
open: false | Array<NavigationLink> | |
/** The entire navigation tree structure */ | |
navigationStructure: NavigationLink | |
} | |
export interface NavigationLink { | |
href: string, | |
title: string, | |
items: Array<NavigationLink> | |
} | |
const createAction = actionCreator<NavigationStore>(); | |
/** | |
* Create a typed reducer for useReducer | |
*/ | |
export const navigationReducer = createReducer({ | |
openNavigation: createAction((state: NavigationStore, option: {}) => { | |
return {...state, open: [state.navigationStructure] } | |
}), | |
closeNavigation: createAction((state: NavigationStore, option: {}) => { | |
return {...state, open: false } | |
}), | |
}); | |
export type NavigationDispatcher = ReducerDispatcher<typeof navigationReducer> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment