Skip to content

Instantly share code, notes, and snippets.

@jtmthf
Created June 3, 2021 20:59
Show Gist options
  • Select an option

  • Save jtmthf/7478d04466e3e9fe0b97f6816b9cd2e3 to your computer and use it in GitHub Desktop.

Select an option

Save jtmthf/7478d04466e3e9fe0b97f6816b9cd2e3 to your computer and use it in GitHub Desktop.
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