statelyai / xstate

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

Type error: Property 'data' does not exist on type 'EventObject' #1384

Closed sumanthyedoti closed 4 years ago

sumanthyedoti commented 4 years ago

Trying assign context value to event.data in an action This is resulting Type Error: Property data does not exist on type EventObject

const fetchMachine = Machine({
  context: {
    result: null,
    error: null,
  },
    //...
  }, {
    actions: {
      setResult: assign((ctx, event) => {
        return {
          result: event.data,
        }
      }),
      setError: assign((ctx, event) => ({
        error: event.data,
      })),  
    },
  }
)
mattpocock commented 4 years ago

This is a known limitation of the current typing system. It can be alleviated by adding an explicit Event type to your Machine:

https://codesandbox.io/s/adoring-ptolemy-4yp9p?file=/src/index.ts

import { Machine, assign, DoneInvokeEvent } from "xstate";

interface Context {}

type Event = DoneInvokeEvent<any>;

export const fetchMachine = Machine<Context, Event>(
  {
    context: {
      result: null,
      error: null
    }
    //...
  },
  {
    actions: {
      setResult: assign((ctx, event) => {
        return {
          result: event.data
        };
      }),
      setError: assign((ctx, event) => ({
        error: event.data
      }))
    }
  }
);
davidkpiano commented 4 years ago

Related to #645 #836 (and probably others)

azs06 commented 2 years ago

I am facing similar issue, tried to solve using the above mentioned solution, still getting that warning message https://codesandbox.io/s/pedantic-oskar-iknohi?file=/src/app.ts

Andarist commented 2 years ago

@azs06 In this case you are trying to access the wrong property of your event. You have declared something like this:

type Event = DoneInvokeEvent<{ page: string }>;

and this is roughly equivalent to:

type Event = {
    type: string;  
    data: { page: string };
}

Therefore you should do this:

        return {
-          currentPage: event.page
+          currentPage: event.data.page
        };

However, note that this probably is not what you are looking for anyway. In most scenarios, you shouldn't ever reach for DoneInvokeEvent yourself. Just declare a regular event and use that. If you actually want to type a "done invoke" event then I recommend using our typegen and reading more on how you can type services here: https://xstate.js.org/docs/guides/typescript.html#typegen