Skip to content

Instantly share code, notes, and snippets.

@anna-bucher
Created September 28, 2018 18:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anna-bucher/95801b59691bdae1bd96af589f9aa9b6 to your computer and use it in GitHub Desktop.
Save anna-bucher/95801b59691bdae1bd96af589f9aa9b6 to your computer and use it in GitHub Desktop.
import { Action, Configuration } from 'overmind'
type SubType<Base, Condition> = Pick<
Base,
{ [Key in keyof Base]: Base[Key] extends Condition ? Key : never }[keyof Base]
>
type TState<Config extends Configuration> = [Config['state']] extends [
undefined
]
? {
[P in keyof SubType<Config['modules'], { state: {} }>]: SubType<
Config['modules'],
{ state: {} }
>[P]['state']
}
: [Config['modules']] extends [undefined]
? Config['state']
: Config['state'] &
{
[P in keyof SubType<Config['modules'], { state: {} }>]: SubType<
Config['modules'],
{ state: {} }
>[P]['state']
}
type TEffects<Config extends Configuration> = [
Config['effects']
] extends [undefined]
? {
[P in keyof SubType<Config['modules'], { effects: object }>]: SubType<
Config['modules'],
{ effects: object }
>[P]['effects']
}
: [Config['modules']] extends [undefined]
? Config['effects']
: Config['effects'] &
{
[P in keyof SubType<Config['modules'], { effects: object }>]: SubType<
Config['modules'],
{ effects: object }
>[P]['effects']
}
type TActions<Config extends Configuration> = [
Config['actions']
] extends [undefined]
? {
[P in keyof SubType<Config['modules'], { actions: object }>]: SubType<
Config['modules'],
{ actions: object }
>[P]['actions']
}
: [Config['modules']] extends [undefined]
? Config['actions']
: Config['actions'] &
{
[P in keyof SubType<Config['modules'], { actions: object }>]: SubType<
Config['modules'],
{ actions: object }
>[P]['actions']
}
function parseModule(
result: { actions: any; effects: any; state: any; initializers: any[] },
modName: string,
mod: Configuration | Function
) {
const { actions, effects, onInitialize, state }: Configuration =
typeof mod === 'function' ? mod(modName) : mod
if (actions) {
result.actions[modName] = actions
}
if (effects) {
result.effects[modName] = effects
}
if (state) {
result.state[modName] = state
}
if (onInitialize) {
onInitialize.displayName = modName + '.onInitialize'
result.initializers.push(onInitialize)
}
}
export function modules<T extends Configuration>(
configWithModules: T
): {
onInitialize?: any
state: TState<T>
effects: TEffects<T>
actions: TActions<T>
} {
const result: any = {
initializers: [],
actions: configWithModules.actions || {},
effects: configWithModules.effects || {},
state: configWithModules.state || {},
}
const modules = configWithModules.modules || {}
Object.keys(modules).forEach((modName) => {
parseModule(result, modName, modules[modName])
})
const onInitialize: Action<undefined> = configWithModules.onInitialize
? configWithModules.onInitialize
: (action) => action.parallel(result.initializers)
// @ts-ignore
onInitialize.displayName = 'onInitialize'
return {
onInitialize,
actions: result.actions,
effects: result.effects,
state: result.state,
}
}
const config = modules({
state: { foo: 'foo'},
modules: {
bar: {
state: {
hello: 'bar'
}
}
}
})
const x = config.state.bar.hello
const y = config.state.foo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment