Skip to content

Instantly share code, notes, and snippets.

@cometkim
Created July 8, 2020 16:11
Show Gist options
  • Save cometkim/18a1afbe3ba1f630cb9b220760320292 to your computer and use it in GitHub Desktop.
Save cometkim/18a1afbe3ba1f630cb9b220760320292 to your computer and use it in GitHub Desktop.
Type guard for XState
export type UserContext = {
};
type UserSuccessContext = UserContext & {
user: User;
};
type UserErrorContext = UserContext & {
error: Error;
};
type UserEvent = (
| { type: 'FETCH'; id: string }
| { type: 'RESOLVE'; user: User }
| { type: 'REJECT'; error: string }
);
type UserStateConfig = (
| { value: 'idle', context: UserContext }
| { value: 'loading', context: UserContext }
| { value: 'success', context: UserSuccessContext }
| { value: 'failure', context: UserErrorContext }
);
export type UserState = StateConfig['value'];
export type GuardUserContext<S extends UserState> = Extract<UserStateConfig, { value: S }>['context'];
export const userMachine = createMachine<UserContext, UserEvent, UserStateConfig>({/* ... */});
// -------------------
// Usage in components
// -------------------
const Component: React.FC = () => {
const [current, send] = useMachine(userMachine);
// Type predicate for TypeState!
function gaurdContext<S extends UserState>(context: UserContext, state: S): context is GuardUserContext<UserState> {
return current.matches(state);
}
return (
<>
{guardContext(current.context, 'success') && (
// typeof current.context is UserSuccessContext here
<span>Hello, {current.context.user.username}!</span>
)}
{guardContext(current.context, 'failure') && (
// typeof current.context is UserErrorContext here
<span>Oops, {current.context.error.message}</span>
)}
</>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment