DEV Community

State machine advent: A safer way to type events and state (11/24)

Mikey Stengel on December 11, 2019

I've worked quite a lot with Ember.js in the past and one of the things I really disliked is how often you have to use strings to perform simple ta...
Collapse
 
fredyc profile image
Daniel K.

I have been using enums a lot in the past (not with xstate), but then I switched over to string unions and it feels much better. I wonder if it could somehow be utilized here as well.

export type TLightSwitchState = "inactive" | "active"

export type TLightSwitchEvent = "TOGGLE"

I am not that well versed with TS yet to figure out the next steps. It would be lovely if we could do something like and it would assemble the correct final type for a machine.

interface LightSwitchStateSchema {
  states: States<TLightSwitchState>
}
Collapse
 
codingdive profile image
Mikey Stengel

It's a cool idea but keep in mind that you also have to use the values to check the current state or to send events. How would you get the light switch event value when doing something like this?

<Switch onChange={() => void send(LIGHT_SWITCH_EVENT.TOGGLE)} />

If you are interested in reducing boilerplate, check out this experimental builder for XState github.com/iliasbhal/xstate-builder and submit machines for the author to look at in this issue.

Collapse
 
fredyc profile image
Daniel K.

The interesting project although it might end up with quite complicated API to cover all cases that XState supports.

As for unions, usually, I do the following when it's hard to have correctly typed one end. It will correctly type-check like that without the need for verbose enum.

export const makeEvent = (name: TLightSwitchEvent) => name

// in the component

send(makeEvent('TOGGLE'))

Not sure why send is not currently typed in this regard. It should ideally be able to infer from the machine itself.

And matches are obvious bigger nut to crack with nesting. I am not sure if TS allows for it dynamically.

Collapse
 
codingdive profile image
Mikey Stengel

Another way is to create a plain JavaScript object from an array using .reduce() which allows you to define each string only once.

const LIGHT_SWITCH_EVENT = [
  'TOGGLE',
  'SOME_OTHER_EVENT',
].reduce((obj, item) => {
  obj[item] = item;
  return obj;
}, {});

// then use it like this: LIGHT_SWITCH_EVENT.TOGGLE

I'll stick to enums as I think they are much easier to read.

Collapse
 
deeds67 profile image
Pierre Marais • Edited

Unfortunately, the standard XState visualizer doesn't work with Typescript. After some googling, I found this github comment describing how to visualize your state machine when using typscript: github.com/statelyai/xstate/issues...

Make sure to allow pop ups on the code sandbox, as it opens up a new tab with the visualizer. Pretty easy to get it working

Collapse
 
oroneki profile image
Oroneki

really good!