Created
June 8, 2017 00:21
-
-
Save NaridaL/8fc965e817d4e6dcf5ea8bee44bbf518 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 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