Created
June 3, 2021 20:59
-
-
Save jtmthf/7478d04466e3e9fe0b97f6816b9cd2e3 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, State, StateSchema, Typestate, createMachine, interpret } from 'xstate'; | |
| type MatchCase< | |
| TContext, | |
| TTypestate extends Typestate<TContext>, | |
| TSV extends TTypestate['value'], | |
| TResult | |
| > = readonly [...TSV[], TResult]; | |
| // TODO: | |
| // - [x] multiple values per case | |
| // - [ ] functional result | |
| // - [ ] type-predicate | |
| export function match< | |
| TContext, | |
| TEvent extends EventObject = EventObject, | |
| TStateSchema extends StateSchema<TContext> = any, | |
| TTypestate extends Typestate<TContext> = { value: any; context: TContext; }, | |
| TSV extends TTypestate['value'] = any, | |
| TResult = any | |
| >(state: State<TContext, TEvent, TStateSchema, TTypestate>, ...cases: MatchCase<TContext, TTypestate, TSV, TResult>[]): TResult | undefined { | |
| for (const matchCase of cases) { | |
| const values = matchCase.slice(0, -1) as TSV[]; | |
| const result = matchCase[matchCase.length - 1] as TResult; | |
| if (values.some(value => state.matches(value))) { | |
| return result; | |
| } | |
| } | |
| return undefined; | |
| } | |
| interface User { | |
| name: string; | |
| } | |
| interface UserContext { | |
| user?: User; | |
| error?: string; | |
| } | |
| type UserEvent = | |
| | { type: 'FETCH'; id: string } | |
| | { type: 'RESOLVE'; user: User } | |
| | { type: 'REJECT'; error: string }; | |
| type UserState = | |
| | { | |
| value: 'idle'; | |
| context: UserContext & { | |
| user: undefined; | |
| error: undefined; | |
| }; | |
| } | |
| | { | |
| value: 'loading'; | |
| context: UserContext; | |
| } | |
| | { | |
| value: 'success'; | |
| context: UserContext & { user: User; error: undefined }; | |
| } | |
| | { | |
| value: 'failure'; | |
| context: UserContext & { user: undefined; error: string }; | |
| }; | |
| const userMachine = createMachine<UserContext, UserEvent, UserState>({ | |
| id: 'user', | |
| initial: 'idle', | |
| states: { | |
| idle: { | |
| /* ... */ | |
| }, | |
| loading: { | |
| /* ... */ | |
| }, | |
| success: { | |
| /* ... */ | |
| }, | |
| failure: { | |
| /* ... */ | |
| } | |
| } | |
| }); | |
| const userService = interpret(userMachine); | |
| userService.subscribe((state) => { | |
| const result = match(state, | |
| ['idle', 'loading', 'no user yet...'], | |
| ['success', 'we have a user'], | |
| ['failure', 'error loading user'] | |
| ) | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment