statelyai / xstate

Actor-based state management & orchestration for complex app logic.
https://stately.ai/docs
MIT License
27.21k stars 1.26k forks source link

Bug: invoke, onDone type incompatibility when `exactOptionalPropertyTypes: true` #5119

Open pauldesmondparker opened 2 weeks ago

pauldesmondparker commented 2 weeks ago

XState version

XState version 5

Description

Reproduction on typescritplang.org.

typescript: v5.6.3 xstate: 5.18.2

Code is the same as the #invoke-and-typescript example with a few tweaks.

Navigate to TS Config and set exactOptionalPropertyTypes. image

The resulting error on onDone will be:

[!CAUTION]

          The types of '_out_TActor.src' are incompatible between these types.
            Type 'string' is not assignable to type '"fetchUser"'. [2322]

[!Note] This only happens when I'm trying to use assign, otherwise no error.

  • (Probably anything in actions will set it off, but I didn't test that).

Expected result

No typescript error.

Actual result

   typescript: Type '{ actions: ActionFunction<{ userId: number; user?: User; }, DoneActorEvent<User, string>, AnyEventObject, undefined, ProvidedActor, never, never, never, never>; }' is not assignable to type 'SingleOrArray<TransitionConfigOrTarget<{ userId: number; user?: User; }, DoneActorEvent<User, string>, AnyEventObject, { src: "fetchUser"; logic: PromiseActorLogic<User, { userId: number; }, EventObject>; id: string | undefined; }, ... 4 more ..., MetaObject>>'.
     Types of property 'actions' are incompatible.
       Type 'ActionFunction<{ userId: number; user?: User; }, DoneActorEvent<User, string>, AnyEventObject, undefined, ProvidedActor, never, never, never, never>' is not assignable to type 'Actions<{ userId: number; user?: User; }, DoneActorEvent<User, string>, AnyEventObject, undefined, { src: "fetchUser"; logic: PromiseActorLogic<User, { ...; }, EventObject>; id: string | undefined; }, never, never, never, EventObject> | undefined'.
         Type 'ActionFunction<{ userId: number; user?: User; }, DoneActorEvent<User, string>, AnyEventObject, undefined, ProvidedActor, never, never, never, never>' is not assignable to type 'ActionFunction<{ userId: number; user?: User; }, DoneActorEvent<User, string>, AnyEventObject, undefined, { src: "fetchUser"; logic: PromiseActorLogic<User, { ...; }, EventObject>; id: string | undefined; }, never, never, never, EventObject>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
           The types of '_out_TActor.src' are incompatible between these types.
             Type 'string' is not assignable to type '"fetchUser"'. [2322]

Reproduction

https://www.typescriptlang.org/play/?exactOptionalPropertyTypes=true&ts=5.6.3#code/JYWwDg9gTgLgBAbzgQwM6uAcwHYBo4BmUEIACsSMKgKb40wCuYcAvoRXAOQAeqMyMapwDccOAHpxcGAE8w1VAC44AVgB0ARgAcagEwAoQ8GyCoBZAGNqcAKo0oifWOAATZdgYgARtSjCncNjIINTKfFDGmP4shtTckLBwFhDYfHAglgAWxtYAvHD0TAAUCAGy8kqOYmLJJnEwyghsaFXVYgz2AJJugZ4+fgFtHb4A-Mp2vv5tLLgBMwGWMNCVpW0E1DAWmRNQykQk5CRU1AA8O-hIw1Dd7n2+rAB8RWgy2BZwJXDGYAzwLACUcFyD1abVqaSgCkgqTyKAA7shgPBDpQaGpIagIAAbABu1BKgzaXx631+aiu3VmROqQRCyk4AAkGJgIJwqUSAVMiZDGFBsHAMdCaFyxAD2fMAWoLJCBNQALJZHIEsSSOBqdUBWqCbgNUFwCk9AAsunF7OMSOAyCx9NcWKE7L4spWhNtoT1YhSjUJbWoLiROwAIhtEViVtJkFBMBt6ViIMg-dhMDtOKx2dM06nCbH45Edl7qcYcRAANZu1bUgpQCz09abbb2Nne6qk3WfLX1ViA4EfcsV-VdHrtnXkgf4VUAFTk1mo2AI0CsLmkEDgPgKMAiiabov+GbaKQDKTLW+qi2AKUqaAwOGVfeqV2Un2oeJMnaBIKfM5gaggvx+MDHUgAMrrikmBYjI0hTouLQ7Me267tU8zUkhiGmvonJAA

Additional context

No response

pauldesmondparker commented 2 weeks ago

Short term remediation:

// @ts-expect-error exactOptionalPropertyTypes
pauldesmondparker commented 2 days ago

Second remediation:

        onDone: {
          actions: ({ event }) => assign({
            user: event.output, // Strongly typed as User
          }),
        },

Making actions an anonymous function, either returning a single action or an array of actions works fine.