Created
April 16, 2019 04:18
-
-
Save ksaldana1/e38d68b6cab352ee395748fb879fe073 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
import { EventObject } from 'xstate'; | |
interface StateSchema<TEvents extends EventObject, TAllStates extends string> { | |
states?: { [K in TAllStates]: StateNode<TEvents, TAllStates> }; | |
} | |
interface StateNode< | |
TEvents extends EventObject, | |
TAllStates extends string, | |
TContext = any | |
> extends StateSchema<TEvents, TAllStates> { | |
context: TContext; | |
transitions: Array<Transition<TEvents, TAllStates>>; | |
} | |
interface Transition<TEvents extends EventObject, TAllStates extends string> { | |
to: TAllStates; | |
event: TEvents; | |
} | |
// I'm sorry Anders... this isn't your fault | |
type ContextMapFromStateSchema< | |
TStateSchema extends StateSchema<any, any> | |
> = TStateSchema['states'] extends Record<infer Keys, any> | |
? { [K in Keys]: TStateSchema['states'][K]['context'] } | |
: never; | |
type ContextUnionFromStateSchema< | |
TStateSchema extends StateSchema<any, any> | |
> = TStateSchema['states'] extends Record<any, infer TStateNode> | |
? TStateNode extends { context: infer TCtx } | |
? TCtx | |
: never | |
: never; | |
type TransitionConfig<T extends StateSchema<any, any>> = { | |
[K in keyof T['states']]: { | |
// oh god oh no | |
on: { | |
[E in T['states'][K]['transitions'][number]['event']['type']]: ActionFunction< | |
ContextMapFromStateSchema<T>[K], | |
Extract<T['states'][K]['transitions'][number]['event'], { type: E }>, | |
ContextMapFromStateSchema<T>[Extract< | |
T['states'][K]['transitions'][number], | |
{ event: { type: E } } | |
>['to']] | |
> | |
}; | |
} | |
}; | |
type ActionFunction<TContext, TEvent extends EventObject, TReturnContext> = ( | |
ctx: TContext, | |
event: TEvent | |
) => TReturnContext; | |
export enum States { | |
EVEN = 'EVEN', | |
ODD = 'ODD', | |
} | |
export enum EventTypes { | |
CLICK = 'CLICK', | |
DOUBLE_CLICK = 'DOUBLE_CLICK', | |
CLEAR = 'CLEAR', | |
} | |
interface ClickEvent { | |
type: EventTypes.CLICK; | |
} | |
interface DoubleClickEvent { | |
type: EventTypes.DOUBLE_CLICK; | |
} | |
interface ExampleSchema { | |
states: { | |
[States.EVEN]: { | |
context: { | |
value: 'EVEN'; | |
}; | |
transitions: [ | |
{ to: States.ODD; event: ClickEvent }, | |
{ to: States.EVEN; event: DoubleClickEvent } | |
]; | |
}; | |
[States.ODD]: { | |
context: { | |
value: 'ODD'; | |
}; | |
transitions: [ | |
{ to: States.EVEN; event: ClickEvent }, | |
{ to: States.ODD; event: DoubleClickEvent } | |
]; | |
}; | |
}; | |
} | |
export const config: TransitionConfig<ExampleSchema> = { | |
[States.ODD]: { | |
on: { | |
CLICK: (_ctx /* ctx is { value: 'ODD' } */, _event) => { | |
return { value: 'EVE' }; | |
}, | |
DOUBLE_CLICK: (_ctx, _event) => { | |
return { value: 'ODD' }; | |
}, | |
}, | |
}, | |
[States.EVEN]: { | |
on: { | |
CLICK: (_ctx /* ctx is { value: 'EVEN' }, */, _event) => { | |
return { value: 'ODD' }; | |
}, | |
}, | |
}, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment