xstate
xstate copied to clipboard
Bug: `AssignAction` type error when using `exactOptionalPropertyTypes: true`
XState version
XState version 5
Description
An assign action reports a type error when using exactOptionalPropertyTypes: true in tsconfig.json.
Expected result
It should be possible to use exactOptionalPropertyTypes: true with xstate.
Actual result
Reproduction
https://stackblitz.com/edit/vitejs-vite-lbw4wa?file=src%2Fmain.ts
Additional context
exactOptionalPropertyTypes allows for more type-safety. It is also recommended when using @effect/schema.
@Andarist is there any workaround for this? Do you know if it's possible to disable exactOptionalPropertyTypes for a specific file?
@Andarist is there any workaround for this? Do you know if it's possible to disable
exactOptionalPropertyTypesfor a specific file?
I updated XState and TypeScript in this codebase and it seems to work fine: https://stackblitz.com/edit/vitejs-vite-lbw4wa?file=package.json,src%2Fmain.ts
Can you double-check that everything's working on your end?
@davidkpiano it seems to be working now when only actions are defined.
When instead I add also actors (as I need in my codebase) the issue comes back: https://stackblitz.com/edit/vitejs-vite-aesqqz?file=package.json,src%2Fmain.ts
@Andarist is there any workaround for this?
I wasn't yet able to figure out a workaround. It's definitely possible to fix this on our side but it requires prioritization and time.
Do you know if it's possible to disable exactOptionalPropertyTypes for a specific file?
No, it's a global setting.
Facing similar issue. Will really appreciate if any workaround is available. Thanks for your time and effort
Facing similar issue. Will really appreciate if any workaround is available. Thanks for your time and effort
Can you share the code that's causing the issue for you?
sure..
import { assign, createActor, fromPromise, setup } from "xstate";
const machine = setup({
types: { context: {} as { value: number } },
actors: {
child: fromPromise(() => Promise.resolve(10))
}
}).createMachine({
id: "test",
initial: "inactive",
context: () => ({ value: 1 }),
invoke: {
src: "child",
onDone: {
actions: assign(({ event }) => ({ value: event.output }))
}
},
states: {
active: { on: { toggle: "inactive" } },
inactive: { on: { toggle: "active" } }
}
});
const actor = createActor(machine);
actor.subscribe(console.log);
actor.start();
Getting following error
error TS2322: Type '{ actions: ActionFunction<{ value: number; }, DoneActorEvent<number, string>, AnyEventObject, undefined, ProvidedActor, never, never, never, never>; }' is not assignable to type 'SingleOrArray<TransitionConfigOrTarget<{ value: number; }, DoneActorEvent<number, string>, AnyEventObject, { src: "child"; logic: PromiseActorLogic<number, NonReducibleUnknown, EventObject>; id: string | undefined; }, ... 4 more ..., MetaObject>>'.
Types of property 'actions' are incompatible.
Type 'ActionFunction<{ value: number; }, DoneActorEvent<number, string>, AnyEventObject, undefined, ProvidedActor, never, never, never, never>' is not assignable to type 'Actions<{ value: number; }, DoneActorEvent<number, string>, AnyEventObject, undefined, { src: "child"; logic: PromiseActorLogic<number, NonReducibleUnknown, EventObject>; id: string | undefined; }, never, never, never, EventObject> | undefined'.
Type 'ActionFunction<{ value: number; }, DoneActorEvent<number, string>, AnyEventObject, undefined, ProvidedActor, never, never, never, never>' is not assignable to type 'ActionFunction<{ value: number; }, DoneActorEvent<number, string>, AnyEventObject, undefined, { src: "child"; logic: PromiseActorLogic<number, NonReducibleUnknown, EventObject>; id: string | undefined; }, never, never, never, EventObject>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property '_out_TActor' are incompatible.
Type 'ProvidedActor' is not assignable to type '{ src: "child"; logic: PromiseActorLogic<number, NonReducibleUnknown, EventObject>; id: string | undefined; }'.
43 onDone: {
~~~~~~
I'm also seeing this sort of error when exactOptionalPropertyTypes is true. I'm using...
- xstate 5.15.0
- TypeScript 5.5.2
Example:
import { timer } from 'rxjs';
import { setup, fromObservable, createActor, assign } from 'xstate';
const machine = setup({
types: { context: {} as { value: number }, events: {} as { type: 'start' } },
actors: {
child: fromObservable(() => timer(5_000)),
},
}).createMachine({
id: 'test',
initial: 'notStarted',
context: { value: 1 },
states: {
notStarted: {
on: {
// Type 'ProvidedActor' is not assignable to type '{ src: "child";...
start: {
target: 'running',
actions: assign({
value: ({ context }) => context.value + 1,
}),
},
},
},
running: {
invoke: {
src: 'child',
onDone: {
target: 'done',
},
},
},
done: { type: 'final' },
},
});
const actor = createActor(machine);
actor.subscribe((snapshot) => console.log(snapshot.value, snapshot));
actor.start();
document.addEventListener('click', () => actor.send({ type: 'start' }));
Produces the following error on the indicated line in the example (start:)
Type '{ target: string; actions: ActionFunction<{ value: number; }, { type: "start"; }, { type: "start"; }, undefined, ProvidedActor, never, never, never, never>; }' is not assignable to type 'TransitionConfigOrTarget<{ value: number; }, { type: "start"; }, { type: "start"; }, { src: "child"; logic: ObservableActorLogic<0, NonReducibleUnknown, EventObject>; id: string | undefined; }, ... 4 more ..., MetaObject>'.
Types of property 'actions' are incompatible.
Type 'ActionFunction<{ value: number; }, { type: "start"; }, { type: "start"; }, undefined, ProvidedActor, never, never, never, never>' is not assignable to type 'Actions<{ value: number; }, { type: "start"; }, { type: "start"; }, undefined, { src: "child"; logic: ObservableActorLogic<0, NonReducibleUnknown, EventObject>; id: string | undefined; }, never, never, never, EventObject> | undefined'.
Type 'ActionFunction<{ value: number; }, { type: "start"; }, { type: "start"; }, undefined, ProvidedActor, never, never, never, never>' is not assignable to type 'ActionFunction<{ value: number; }, { type: "start"; }, { type: "start"; }, undefined, { src: "child"; logic: ObservableActorLogic<0, NonReducibleUnknown, EventObject>; id: string | undefined; }, never, never, never, EventObject>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property '_out_TActor' are incompatible.
Type 'ProvidedActor' is not assignable to type '{ src: "child"; logic: ObservableActorLogic<0, NonReducibleUnknown, EventObject>; id: string | undefined; }'.ts(2322)
I'm also seeing this type error with exactOptionalPropertyTypes: true with
- xstate 5.17.4
- typescript 5.1.3
As @SandroMaglione noted, the issue only manifests when at least one actors is defined. But the weird part is that it is not localized to actions with actors... As soon as an actor is defined, even assign actions that are not connected to actors also get type errors.
Here's a variation of @bhvngt's example to illustrate:
import { assign, createActor, fromPromise, setup } from 'xstate';
const machine = setup({
types: { context: {} as { value: number } },
/////////// Comment this chunk out and the type error on "toggle" disappears
actors: {
child: fromPromise(() => Promise.resolve(10)),
},
///////////////// end chunk
}).createMachine({
id: 'test',
initial: 'inactive',
context: () => ({ value: 1 }),
states: {
active: {
on: {
// Type error on `toggle` here
toggle: { target: 'inactive', actions: assign({ value: () => 0 }) },
},
},
inactive: { on: { toggle: 'active' } },
},
});
const actor = createActor(machine);
Link to stackblitz: https://stackblitz.com/edit/node-lsnym4?file=index.ts