Skip to content

Instantly share code, notes, and snippets.

@NaridaL
Created June 8, 2017 00:21
Show Gist options
  • Save NaridaL/8fc965e817d4e6dcf5ea8bee44bbf518 to your computer and use it in GitHub Desktop.
Save NaridaL/8fc965e817d4e6dcf5ea8bee44bbf518 to your computer and use it in GitHub Desktop.
export type KeysToTrue<T> = {
[P in Key<T>]: true;
}
export type Key<T> = keyof T
export type Mapping<T, S> = {
[P in Key<T>]: S
}
type Mapper<T, S> = (value: T[Key<T>], key: Key<T>) => S
export function mapObject<T, S>(f: Mapper<T, S>, obj: T): Mapping<T, S> {
const result: Mapping<T, S> = {} as any
const keys = Object.keys(obj) as Key<T>[]
for (const key of keys) {
result[key] = f(obj[key], key)
}
return result
}
type Reducer<STATE, ACTION> = (state: STATE, action: ACTION) => STATE
export interface Handler<S, ACTION_PARAM> {
[key: string]: Reducer<S, ACTION_PARAM>
}
interface Action<P> {
readonly type: string
payload: P
}
function actionCreatorCreator<K, P>(key: K) {
return (payload: P) => ({
type: key,
payload,
})
}
export default function createModule<ACTION_TYPES, S>(
initial: S,
handler: {[K in keyof ACTION_TYPES]: Reducer<S, Action<ACTION_TYPES[K]>>})
: { reducer: any, actions: {[K in keyof ACTION_TYPES]: (p: ACTION_TYPES[K]) => void}}
{
const reducer = (state = initial, action: Action<any>) => {
return handler[action.type] ? handler[action.type](state, action) : state
}
const actions = mapObject((v, key) => {
// any way to get the type of the payload? i.e.
// return actionCreatorCreator<keyof R, getgenericfrom R[keyof R]>
return actionCreatorCreator(key)
}, handler)
const types: Key<R>[] = Object.keys(handler)
return { reducer, actions, types }
}
const myModule = createModule<{increment: number, decrement: number, string_replace:string}, number>(0, {
increment: (state, action: Action<number>) => state + action.payload,
decrement: (state, action: Action<number>) => state - action.payload,
string_replace: (state, action: Action<string>) => parseInt(action.payload, 10),
})
const myModule2 = createModule(0, {
increment: (state, action: Action<number>) => state + action.payload,
decrement: (state, action: Action<number>) => state - action.payload,
string_replace: (state, action: Action<string>) => parseInt(action.payload, 10),
})
type H = typeof myModule.actions
// this should not be allowed
myModule.actions.string_replace({})
myModule.actions.increment("wat")
myModule2.actions.string_replace({})
myModule2.actions.increment("wat")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment