solid-primitives
solid-primitives copied to clipboard
createCookieStorage cannot be explicitly typed
The storage object returned by createCookieStorage returns a StorageObject<any>. I wanted to get rid of the any and use a stronger type, so I tried this:
const [settings, getSettings] = createCookieStorage<IAppSettings>();
However, this doesn't work - the getter has the correct type that I would expect - it's type is StorageObject<IAppSettings>. However, the setter has the wrong type:
setSettings(key: string, value: IAppSettings)
In other words, the type signature is such that it wants you to pass the entire storage object instead of a single keyed value, which is inconsistent with how the function actually works.
What the setter ought to look like is something along these lines:
setSettings<Key extends keyof IAppSettings>(key: Key, value: IAppSettings[Key])
Also, I noticed that the docs say that you can use the cookie store "just like createStore", but this is not true - the setters produced by createStore have a lot more options (you can pass in a function etc.). Or at least, the TypeScript function signature for the setter doesn't have any of those options defined - you can only pass in a value.
So either these features should be added, or the docs corrected, because at the moment I was very confused when I tried to use the setters in that way.
That doesn't work, because you are not using any (de)serialization, so all you can have is a Record<string, string>, because that's what Storage saves.
Without a deserializer, what storage saves is the string "[Object object]" which is probably not what you want. Perhaps the serializer should be mandatory instead of optional? (And it has to be an object, not a primitive type - because otherwise the proxy mechanism of stores wouldn't work.)
Why should it be mandatory? If all you want to store is strings, that would be unnecessary overhead.
It matches the browser behavior by default. So nothing wrong here I think.

Maybe the misunderstanding here is that we are not substituting createStore here, but instead abstracting the Storage standard into a primitive. I think we need better documentation.
Let me try and explain my confusion in more detail.
The documentation for createCookieStore says that it's a "reactive" store. Since the 'getter' value returned by createCookieStore is not a function, that means that the store has to be either an object proxy or an array proxy - there's no way for primitive values, by themselves, to be reactive. A store which was of type "string" could not be reactive. So the statement about the store being reactive caused me to make certain assumptions.
The documentation also states "is meant to wrap any localStorage-like API to be as accessible as a Solid Store". However, the API isn't much like a Solid Store from what I can tell.
Take for example my use case: I want to store a set of user preferences in a cookie. Since I like to strongly type everything, my preferences type looks like this:
interface Prefs {
darkMode?: boolean;
showSource?: boolean;
selectedComponent?: string;
}
This is to be stored in a single cookie as a serialized object. So I'm assuming that I can access these preferences using a cookie store:
const [prefs, setPrefs] = createCookieStore(.../etc/...);
And I would access the prefs as follows:
if (prefs.darkMode) {
// Render dark mode toggle with "dark" selected
} else {
// Render dark mode toggle with "light" selected
}
OK so now I want to update the store when the user changes preferences, so I assumed it would be something like this:
setPrefs('darkMode', true);
...in other words, because the setter takes a key as the first parameter, I assume that key is the name of the property in the store object to be replaced. However, apparently that's not how it works. Instead, the second argument appears to be (according to the TypeScript type declarations) the entire store object, not just a single property.
If that is indeed the case, then I am not sure what the first argument means. If it's not the name of the property to be modified, then what is it? I guess it means the key used to store the entire item in local / session / cookie storage. But this in turn means that there can only be one local store / cookie store / etc - unlike Solid stores where you can create multiple stores and each is a separate namespace.
Now, in a regular Solid Store, there would normally only be one argument, which is merged with the store. So I would call:
setPrefs({ darkMode: true });
...which is very different from the API of the cookie store.
Yes, as I said, it is not a regular Solid store, but an abstraction of the Storage API that is a web standard. I really need to update the docs. Also, we can probably also add a createStorageStore in this primitive as a simple abstraction. That being said, the decision to do this from the standard and merely add reactivity instead of going from a store was one meant to bring maximum performance, as serialization is quite slow.
@atk P.S. On that createStorageStore idea: If you are interested in some inspiration, I implemented one here: https://git.lufrai.org/rappli/rappli/src/branch/master/src/localStore.ts :)
Since createCookieStorage is now deprecated, I'll close this issue.