xstate icon indicating copy to clipboard operation
xstate copied to clipboard

Inspector does not stringify Map() and Set() objects

Open VanTanev opened this issue 3 years ago • 4 comments

Description

If the context of a machine uses new Map() / new Set(), both get stringified as {}

Expected Result

Map() should be stringified as an object, and Set as an array


Workaround

function betterToJSON<T extends Record<string, any>>(obj: T): T {
    if (process.env.NODE_ENV === 'development' && typeof obj === 'object') {
        ;(obj as any)['toJSON'] = function (this: Record<string, unknown>) {
            const keys = Object.keys(this)
            const res = { ...this }
            for (let key of keys) {
                const value = this[key]
                if (value instanceof Set) {
                    res[key] = [...value]
                }
                if (value instanceof Map) {
                    res[key] = Object.fromEntries([...value])
                }
            }
            return res
        }
    }
    return obj
}

const machine = createMachine({
  context: betterToJSON({
    normal: 'field',
    set: new Set([1, 2, 3]),
    map: new Map([['a', 1], ['b', 2]])
  })
})

VanTanev avatar Apr 21 '21 16:04 VanTanev

This is also the story when using redux / redux dev tools etc., every step of the way you get punished for using modern javascript data structures 😆

Would be beyond awesome if using Map and Set with xstate would "just work".

johtso avatar Jul 04 '21 18:07 johtso

This is also the story when using redux / redux dev tools etc., every step of the way you get punished for using modern javascript data structures 😆

Would be beyond awesome if using Map and Set with xstate would "just work".

It does "just work" in XState, just not with the inspector 😓

davidkpiano avatar Jul 04 '21 20:07 davidkpiano

I guess one of the the potential pain points is persistence, but xstate leaves that to the user so it's up to you to use the right serialisation approach (e.g. orjson).

johtso avatar Jul 05 '21 09:07 johtso

Just ran into this, was pretty confusing until I started using the console.

j-funk avatar May 05 '22 23:05 j-funk

inspect(...) can take in a serializer:

inspect({
  iframe: false,
  devTools,
  serialize: (_key, value) => {
    if (value instanceof Map) {
      // convert map to object
    }

    return value;
  }
});

davidkpiano avatar Apr 11 '23 01:04 davidkpiano