You will notice a type error with invoke:
Property 'input' is missing in type [...]Since submitActor requires an input we need to pass it when executing the actor.
Take a moment to notice how since XState v5 most properties are completely type safe by default! 💯
We pass the input by defining input inside the invoke object:
const machine = setup({
types: {
context: {} as Context,
events: {} as Event,
},
actors: { submitActor },
}).createMachine({
context: initialContext,
initial: "Editing",
states: {
Editing: {
on: {
"update-username": {
actions: assign(({ event }) => ({
username: event.username,
})),
},
submit: { target: "Loading" },
},
},
Loading: {
invoke: {
src: "submitActor",
input: ({ event, context }) => {
// Return the input for the submitActor
},
},
},
},
});XState provides a helper function called assertEvent.
assertEventwill throw an error if the event is not of the expected type.
We use assertEvent to verify the event as submit, extract event and return the input for the submitActor:
const machine = setup({
types: {
context: {} as Context,
events: {} as Event,
},
actors: { submitActor },
}).createMachine({
context: initialContext,
initial: "Editing",
states: {
Editing: {
on: {
"update-username": {
actions: assign(({ event }) => ({
username: event.username,
})),
},
submit: { target: "Loading" },
},
},
Loading: {
invoke: {
src: "submitActor",
input: ({ event, context }) => {
// 👇 Only "submit" contains `event` required as input to the actor
assertEvent(event, "submit");
return { event: event.event, context };
},
},
},
},
});Since any event may cause the transition to the "Loading" state, we need to explicitly check that the event is of type
submitbefore extractingeventand returning the input for thesubmitActor.Otherwise, the only thing we can do is throwing an error.
The submit event contains React.FormEvent<HTMLFormElement> that we pass to the submitActor as input.
type Event =
| { type: "update-username"; username: string }
| { type: "submit"; event: React.FormEvent<HTMLFormElement> };
const submitActor = fromPromise(
async ({
input,
}: {
input: { event: React.FormEvent<HTMLFormElement>; context: Context };
}) => {
input.event.preventDefault();
await postRequest(input.context);
}
);