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: Property '[Symbol.observable]' is missing in type - useSelector TS error #3141

Closed
davydof opened this issue Mar 10, 2022 · 5 comments · Fixed by #3146
Closed

Bug: Property '[Symbol.observable]' is missing in type - useSelector TS error #3141

davydof opened this issue Mar 10, 2022 · 5 comments · Fixed by #3146

Comments

@davydof
Copy link

davydof commented Mar 10, 2022

Description

Hi, I'm migrating from old @xstate/react: 0.8.* and updating the code

I set machine types by createMachine<ToggleMachineContext, ToggleMachineEvent>({}) and try to use useSelector to get value from machine context but I get an error :/

TS2345: Argument of type 'Interpreter<ToggleMachineContext, any, ToggleEvent, { value: any; context: ToggleMachineContext; }, TypegenDisabled>'
is not assignable to parameter of type 'ActorRef<any, any>'.

Property '[Symbol.observable]' is missing in type
'Interpreter<ToggleMachineContext, any, ToggleEvent, { value: any; context: ToggleMachineContext; }, TypegenDisabled>'
but required in type 'ActorRef<any, any>'. 

types.d.ts(981, 5): '[Symbol.observable]' is declared here.

What I do wrong?
Could you please provide the example with working TS types?

Thank you!

In codesandbox I get another error :/

Expected result

No errors expected

Actual result

image

Reproduction

https://codesandbox.io/s/still-breeze-8iqd6w?file=/src/index.tsx

Additional context

import { useMachine, useSelector } from '@xstate/react';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { assign, createMachine } from 'xstate';

interface ToggleMachineContext {
  count: number;
}

interface ToggleEvent {
  type: 'TOGGLE';
}

type ToggleMachineEvent = ToggleEvent;

const toggleMachine = createMachine<ToggleMachineContext, ToggleMachineEvent>({
  id: 'toggle',
  initial: 'inactive',
  context: {
    count: 0,
  },
  states: {
    inactive: {
      on: { TOGGLE: 'active' },
    },
    active: {
      entry: assign({ count: (ctx) => ctx.count + 1 }),
      on: { TOGGLE: 'inactive' },
    },
  },
});

function App() {
  const [state, send, service] = useMachine(toggleMachine);
  const active = state.matches('active');

  const countFromSelector = useSelector(
    service,
    ({ context }) => context.count,
  );
  console.log('countFromSelector', countFromSelector);

  const count = state.context.count;
  console.log('count', count);

  return (
    <div className="App">
      <h1>XState React Template</h1>
      <h2>Fork this template!</h2>
      <button onClick={() => send('TOGGLE')}>
        Click me ({active ? '✅' : '❌'})
      </button>{' '}
      <code>
        Toggled <strong>{count}</strong> times
      </code>
    </div>
  );
}

const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
@xstate/react: 1.6.3
typescript: 3.9.9
xstate: 4.30.5
@davydof davydof added the bug label Mar 10, 2022
@davidkpiano
Copy link
Member

Make sure you're on the latest version of @xstate/react (2.0.x): https://codesandbox.io/s/busy-panna-7ig67r?file=/src/index.tsx

I cannot reproduce the type issue with the upgraded version ☝️

@davydof
Copy link
Author

davydof commented Mar 10, 2022

no, the @xstate/react version is 1.6.3 - I have TS 3.9.9 so I can't bump @xstate/react to 2.0.x version

@Andarist
Copy link
Member

I'm investigating this, for my own reference this is a simplified repro that doesn't involve @xstate/react directly: TS playground.

For some weird reason the type for the TEvent within useMachine call gets inferred to EventObject (where your StateMachine actually contains ToggleMachineEvent). You can work around this by providing explicit generics to the useMachine call, like this:

function App() {
-  const [state, send, service] = useMachine(toggleMachine);
+  const [state, send, service] = useMachine<ToggleMachineContext, ToggleMachineEvent>(toggleMachine);

This is, of course, less than ideal - so I'm just proposing as a temporary workaround for this issue.

However, this only "fixes" the problem presented on this codesandbox and your original issue is a different issue. Could you try to prepare a repository for this problem (since you were not able to repro that on codesandbox)?

@Andarist
Copy link
Member

I was able to slim down the repro case for this issue, even more, see this TS playground.

It's quite fascinating because I was able to annotate 4 (sic!) places that are required to be there to trigger the problem. When uncommenting any of them the problem goes away. Luckily, I was also able to figure out a fix for this using NoInfer.

At the same time I think that we should hide almost everything from the StateMachine class in the future. It doesn't have to have all of those properties, especially not as public ones. Those are not supposed to be used publicly and internally they could use simpler types that wouldn't be based on generics. This would help with not running into issues like this caused by a very complex internal structure and most likely it would improve the type checking performance quite a bit. The last thing is especially important when we consider "full structural variance computation" that is coming to TS (which is going to fix some issues in XState by the way), just take a look at the traversal of one of our types that Anders has provided here. Notice how the biggest chunk here is printed just below the StateMachine type - and I believe that removing most of those properties from the StateMachine class would just entirely remove this huge~ branch of computation.

@davydof
Copy link
Author

davydof commented Mar 10, 2022

thank you for help

@Andarist to reproduce the issue try this repo

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

Successfully merging a pull request may close this issue.

3 participants