`persisted` throws when getting value `undefined` (because of `JSON.parse(undefined))`)
acedeb opened this issue · comments
Current Behavior
Initially posted here: skeletonlabs/skeleton#2266
When initializing or setting the persisted
with undefined
the store throws an error when trying to parse undefined
, and the site is not rendered.
// lib/stores.ts
export const idStore: Writable<string | undefined> = localStorageStore(
"some-id",
undefined,
);
// routes/+page.svelte
<script>
import { idStore } from '$lib/stores'
idStore.set(undefined);
console.log(`idStore: ${$idStore}`);
</script>
Expected Behavior
Would expect the store to return undefined
. This works correctly when using e.g. null
instead, as JSON.parse(null)
returns null.
Solution
I'm a bit unsure what the best solution is, as I don't think we can differentiate between a getting undefined
or getting a string "undefined"
. AFAIK, when setting undefined
this become the string "undefined"
.
I can think of 2 solutions (if its not possible to differentiate between "undefined"
and undefined
):
- We need to check it the variable json is equal to the string
"undefined"
where we would returnundefined
instead. This, however, will cause a bug when someone tries to get the string"undefined"
, but getsundefined
instead, so not good. - We ban
undefined
in the generic type parameterT
, which forces people to usenull
instead. I think I prefer this.
Link to Reproduction / Stackblitz
https://stackblitz.com/edit/sveltejs-kit-template-default-4uen9v?file=src%2Froutes%2F%2Bpage.svelte
If you'd like to use data types that are unsupported by JSON.stringify()
/JSON.parse()
, switch the serializer
to devalue
.
Here is an example from the Readme:
import * as devalue from 'devalue'
// third parameter is options.
export const preferences = persisted('local-storage-key', 'default-value', {
serializer: devalue, // defaults to `JSON`
})
Let me know if that resolves the issue for you.
Thank you for answering.
Yes, this solves the issue. In my case, I can also use null
instead of undefined
, but I usually just default to undefined
.
I do think though, that in general it would be nice to not having to know the internals of the library, i.e. that persisted
is using JSON
underneath, for me to know that undefined
is not supported (by default), and will throw. Since undefined
is working when using svelte writable
, my (smooth) brain assumed that it would work here as well (though one can argue that of course it would be using JSON parser since we are retrieving the value from localstorage).
I don't know really know what you could change though in this case, so closing this.
'devalue' seems very interesting - thanks for pointing me to that as well.