Description
I'm building a state machine according to xstate documentation.
It's a pretty simple example. I'm using action setCustomerDataFromResponse in loading state invoke onDone, and get the error during webpack bundle.
Issue with the
actions: {
setCustomerDataFromResponse: assign<CustomerModalContext>({
response: (_, event) => event.data.response,
}),
},
Expected Result
Webpack bundle
Actual Result
[tsl] ERROR in ...\src\machines\machine-example.ts(53,7)
TS2322: Type 'AssignAction<CustomerModalContext, EventObject>' is not assignable to type 'ActionObject<CustomerModalContext, CustomerModalEvent> | ActionFunction<CustomerModalContext, CustomerModalEvent>'.
Type 'AssignAction<CustomerModalContext, EventObject>' is not assignable to type 'ActionObject<CustomerModalContext, CustomerModalEvent>'.
Types of property 'exec' are incompatible.
Type 'ActionFunction<CustomerModalContext, EventObject>' is not assignable to type 'ActionFunction<CustomerModalContext, CustomerModalEvent>'.
Types of parameters 'meta' and 'meta' are incompatible.
Type 'ActionMeta<CustomerModalContext, CustomerModalEvent>' is not assignable to type 'ActionMeta<CustomerModalContext, EventObject>'.
The types of 'state.configuration' are incompatible between these types.
Type 'StateNode<CustomerModalContext, any, CustomerModalEvent, any>[]' is not assignable to type 'StateNode<CustomerModalContext, any, EventObject, any>[]'.
Type 'StateNode<CustomerModalContext, any, CustomerModalEvent, any>' is not assignable to type 'StateNode<CustomerModalContext, any, EventObject, any>'.
The types of 'config.invoke' are incompatible between these types.
Type 'SingleOrArray<InvokeConfig<CustomerModalContext, CustomerModalEvent>>' is not assignable to type 'SingleOrArray<InvokeConfig<CustomerModalContext, EventObject>>'.
Type '{ id?: string; src: string | StateMachine<any, any, any, any> | InvokeCreator<CustomerModalContext, CustomerModalEvent, any>; ... 4 more ...; onError?: string | ... 1 more ... | TransitionConfig<...>[
]; }' is not assignable to type 'SingleOrArray<InvokeConfig<CustomerModalContext, EventObject>>'.
Type '{ id?: string; src: string | StateMachine<any, any, any, any> | InvokeCreator<CustomerModalContext, CustomerModalEvent, any>; ... 4 more ...; onError?: string | ... 1 more ... | TransitionConfig<...
>[]; }' is not assignable to type '{ id?: string; src: string | StateMachine<any, any, any, any> | InvokeCreator<CustomerModalContext, EventObject, any>; ... 4 more ...; onError?: string | ... 1 more ... | TransitionConfig<...>[
]; }'.
Types of property 'src' are incompatible.
Type 'string | StateMachine<any, any, any, any> | InvokeCreator<CustomerModalContext, CustomerModalEvent, any>' is not assignable to type 'string | StateMachine<any, any, any, any> | InvokeCreator<Cus
tomerModalContext, EventObject, any>'.
Type 'InvokeCreator<CustomerModalContext, CustomerModalEvent, any>' is not assignable to type 'string | StateMachine<any, any, any, any> | InvokeCreator<CustomerModalContext, EventObject, any>'.
Type 'InvokeCreator<CustomerModalContext, CustomerModalEvent, any>' is not assignable to type 'InvokeCreator<CustomerModalContext, EventObject, any>'.
Types of parameters 'event' and 'event' are incompatible.
Type 'EventObject' is not assignable to type 'CustomerModalEvent'.
Reproduction
Here's the smallest reproduction I can come up with.
import { assign, DoneEventObject, Machine } from 'xstate';
export const fetchCustomer = (): Promise<any> =>
Promise.resolve({
id: '2352357',
firstName: 'John',
lastName: 'Smith',
});
interface CustomerModalContext {
response: {
id: string;
firstName: string;
lastName: string;
};
}
interface CustomerModalSchema {
states: {
loading: {};
initial: {};
};
}
type CustomerModalEvent = { type: 'INITIALIZED' };
const customerModalMachine = Machine<CustomerModalContext, CustomerModalSchema, CustomerModalEvent>(
{
initial: 'loading',
context: {
response: undefined,
},
states: {
loading: {
invoke: {
src: 'fetchCustomer',
onDone: [
{
target: 'initial',
actions: 'setCustomerDataFromResponse',
},
],
},
},
initial: {},
},
},
{
services: {
fetchCustomer: (context) => fetchCustomer(),
},
actions: {
setCustomerDataFromResponse: assign<CustomerModalContext>({
response: (_, event) => event.data.response,
}),
},
},
);
Additional context
"xstate": "^4.10.0",
"webpack": "^4.43.0",
In case I'm doing something completely wrong: Any kind of feedback highly appreciated!
In TS whenever you pass a type parameter you turn off the inference for the rest of arguments and defaults are used. So you have to provide all type parameters yourself if you provide any.
Thanks Andarist for the help!
I tried everything, with inference and without inference.
In this case:
actions: {
setCustomerDataFromResponse: assign<CustomerModalContext, DoneEventObject>({
response: (_, event) => event.data.response,
}),
},
Error:
....
to type 'InvokeCreator<CustomerModalContext, DoneEventObject, any>'. 聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽
Types of parameters 'event' and 'event' are incompatible. 聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽
Type 'DoneEventObject' is not assignable to type 'CustomerModalEvent'.
This is currently a shortcoming of our typings which is really hard to fix - given TS limitations. I would recommend just adding an appropriate event type (which would extend DoneEventObject to improve soundness) to your CustomerModalEvent. After all, this would be correct - your machine is accepting such an event, you just haven't declared it to be accepted up to this point.
type CustomerModalEvent =
| { type: 'COMPLETE' }
| { type: 'INITIALIZED' }
| { type: 'RETRY' }
| { type: 'COPY' }
| { type: 'EXIT' }
| { type: 'INITIALIZED' }
I'm still learning XState.
I have many events. Can you, please, provide an example in my case. How I should extend?
And how the events are related to the onDone actions? I don't send any events.
onDone is just a sugar syntax over something like:
on: {
'done.invoke.id': { /* */ }
}
Such an event is actually sent from the invoked service to the invoking one under the hood.
I have many events. Can you, please, provide an example in my case. How I should extend?
If you prepare a runnable repro case of your problem using CodeSandbox or similar then I could propose a fix for you.
https://github.com/liam33893/webpack-ts-xstate-error/
I created the smallest possible repo with the error here on GitHub as an example.
Just run npm run build. The error will be there.
I really appreciate your help. Thanks
@liam33893 Can you put that in a CodeSandbox instead?
Sure.
Here is the link - https://codesandbox.io/s/bold-frost-ccfjb?file=/webpack.config.js
In terminal run npm run build. If terminal is in read-only, click create terminal.
Thanks
Hey @liam33893, I don't see any TypeScript errors in the CodeSandbox provided.
Yes. The error appears only when you run npm run build in the terminal. Click on the terminal and type something, dialog window should popup with button create terminal, then you can run any npm scripts there.
We can probably improve the types here, but it has a simple workaround:
type CustomerModalEvent = { type: 'INITIALIZED' } | DoneEventObject;
Try that.
Thank you guys for the help. That did the trick.
Most helpful comment
We can probably improve the types here, but it has a simple workaround:
Try that.