xstate
xstate copied to clipboard
Inspector does not stringify Map() and Set() objects
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]])
})
})
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".
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 😓
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).
Just ran into this, was pretty confusing until I started using the console.
inspect(...)
can take in a serializer:
inspect({
iframe: false,
devTools,
serialize: (_key, value) => {
if (value instanceof Map) {
// convert map to object
}
return value;
}
});