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: Typegen fails to infer types of imported actions/etc #410

Open
parker-codes opened this issue Sep 7, 2022 · 6 comments
Open

Bug: Typegen fails to infer types of imported actions/etc #410

parker-codes opened this issue Sep 7, 2022 · 6 comments
Assignees
Labels
bug Something isn't working typegen

Comments

@parker-codes
Copy link

parker-codes commented Sep 7, 2022

Description

If I use typegen with all options inside of the same file, the types work as expected. If I move any of these options to an external file, typegen cannot infer the method signatures on either end.

Expected result

The tyepgen service could follow the import to correctly infer the type signature of the imported action. Then within the action, I could add type hints to correctly see what the parameters are.

Actual result

A rather long error block is shown underneath the action declaration.

Reproduction

https://github.com/parker-codes/xstate-typegen-import-error

Additional context

There is an xstate:typegen command defined in package.json to generate the types.

Remove either of the two lines that say // @ts-expect-error XState Typegen to view the errors.

@parker-codes parker-codes added the bug Something isn't working label Sep 7, 2022
@Andarist
Copy link
Member

Andarist commented Sep 7, 2022

This is expected - typegen generates some extra data to aid inference. Inference only works when the contextual type can flow into an expression. In your case, incrementCount is already predefined elsewhere and thus its type is already "set in stone".

@parker-codes
Copy link
Author

@Andarist is there no way to facilitate sharing code between machines then and still have them typed? Perhaps using a different strategy to remove the "set in stone" functionality?

@Andarist
Copy link
Member

Andarist commented Sep 7, 2022

This does the trick:

Possible patch that utilizes `MachineOptionsFrom`
diff --git a/src/machines/actions.ts b/src/machines/actions.ts
index e941abc..90a8133 100644
--- a/src/machines/actions.ts
+++ b/src/machines/actions.ts
@@ -1,7 +1,9 @@
-import { assign } from "xstate";
+import { assign, MachineOptionsFrom } from "xstate";
+import type { ToggleMachine } from "./toggle.machine";
 
-export const incrementCount = assign((ctx) => ({
-  // Object is of type 'unknown'.
-  // @ts-expect-error XState Typegen
+export const incrementCount: MachineOptionsFrom<
+  ToggleMachine,
+  true
+>["actions"]["incrementCount"] = assign((ctx) => ({
   count: ctx.count + 1,
 }));
diff --git a/src/machines/toggle.machine.ts b/src/machines/toggle.machine.ts
index 8a8212d..f72734f 100644
--- a/src/machines/toggle.machine.ts
+++ b/src/machines/toggle.machine.ts
@@ -7,42 +7,42 @@ interface ToggleContext {
 
 type ToggleEvent = { type: "TOGGLE" } | { type: "RESET" };
 
-export const toggleMachine = createMachine(
-  {
-    id: "toggle",
-    preserveActionOrder: true,
-    initial: "off",
-
-    schema: {
-      context: {} as ToggleContext,
-      events: {} as ToggleEvent,
-    },
-    tsTypes: {} as import("./toggle.machine.typegen").Typegen0,
+const _toggleMachine = createMachine({
+  id: "toggle",
+  preserveActionOrder: true,
+  initial: "off",
 
-    context: {
-      count: 0,
-    },
+  schema: {
+    context: {} as ToggleContext,
+    events: {} as ToggleEvent,
+  },
+  tsTypes: {} as import("./toggle.machine.typegen").Typegen0,
 
-    states: {
-      off: {
-        on: {
-          TOGGLE: {
-            actions: ["incrementCount"],
-            target: "on",
-          },
+  context: {
+    count: 0,
+  },
+
+  states: {
+    off: {
+      on: {
+        TOGGLE: {
+          actions: ["incrementCount"],
+          target: "on",
         },
       },
+    },
+    on: {
       on: {
-        on: {
-          TOGGLE: "off",
-        },
+        TOGGLE: "off",
       },
     },
   },
-  {
-    actions: {
-      // @ts-expect-error XState Typegen
-      incrementCount,
-    },
-  }
-);
+});
+
+export type ToggleMachine = typeof _toggleMachine;
+
+export const toggleMachine = _toggleMachine.withConfig({
+  actions: {
+    incrementCount,
+  },
+});

@Osky772
Copy link

Osky772 commented Feb 16, 2023

@Andarist following your example I have a TS error in actions.ts:
Property 'incrementCount' does not exist on type 'MachineOptionsActions<ToggleContext, ResolveTypegenMeta<Typegen0, { type: "TOGGLE"; } | { type: "RESET"; }, BaseActionObject, ServiceMap>, { ...; }, MergeWithInternalEvents<...>, IndexByType<...>> | undefined'.ts(2339)

@Andarist
Copy link
Member

Please always try to share a repro case in a runnable form - either by providing a git repository to clone or a codesandbox. I can’t debug a lot from an error message 😉

@Osky772
Copy link

Osky772 commented Feb 16, 2023

Actually, finally, I get this working. I think that just it was hard to reproduce the code from the git diff. Anyway, thanks!

@davidkpiano davidkpiano transferred this issue from statelyai/xstate Nov 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working typegen
Projects
None yet
Development

No branches or pull requests

4 participants