Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: AssignAction type error when using exactOptionalPropertyTypes: true #4613

Open
SandroMaglione opened this issue Dec 22, 2023 · 12 comments
Assignees
Labels

Comments

@SandroMaglione
Copy link
Contributor

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.

@SandroMaglione
Copy link
Contributor Author

@Andarist is there any workaround for this? Do you know if it's possible to disable exactOptionalPropertyTypes for a specific file?

@davidkpiano
Copy link
Member

@Andarist is there any workaround for this? Do you know if it's possible to disable exactOptionalPropertyTypes for 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?

@SandroMaglione
Copy link
Contributor Author

@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
Copy link
Member

@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.

@bhvngt
Copy link

bhvngt commented Jul 12, 2024

Facing similar issue. Will really appreciate if any workaround is available. Thanks for your time and effort

@davidkpiano
Copy link
Member

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?

@bhvngt
Copy link

bhvngt commented Jul 12, 2024

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: {
           ~~~~~~

@michael-wisely-gravwell

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)

@khusmann
Copy link

khusmann commented Aug 19, 2024

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

@lukeramsden
Copy link

Also seeing this. Seems like only option is to disabled exactOptionalPropertyTypes for now which isn't ideal but not the end of the world.

@kadeer
Copy link

kadeer commented Nov 30, 2024

I also see the same error in my codebase as well as the samples above when an actor object is set in the setup object with exactOptionalPropertyTypes: true in tsconfig.json.

image
  • Typescript 5.7.2
  • XState 5.19.0

We have a huge codebase we are introducing XState V5 into where exactOptionalPropertyTypes: true has served us well at catching and keeping bugs out, so turning off exactOptionalPropertyTypes isn't an option for us. Are there fixes for this issue coming soon, or workarounds anyone can suggest to keep us moving forward?

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants