S
SolidJS•13mo ago
Braveheart

Typesafe <Show> only when store has data

the end result I want
return (
<Show when={mockDataStore}>
{mockDataStore.prop} // don't want this to be called giving runtime errors on render when mockDataStore has empty object
return (
<Show when={mockDataStore}>
{mockDataStore.prop} // don't want this to be called giving runtime errors on render when mockDataStore has empty object
I've tried various things like createStore<StoreType | {}>({}); -> results in ts errors X doesn't exist on {} re assigning store to previous declarations
const [mockDataStore2, setMockDataStore2] = createStore<StoreType | {}>({});

mockDataStore = mockDataStore2;
setMockDataStore = setMockDataStore2;
const [mockDataStore2, setMockDataStore2] = createStore<StoreType | {}>({});

mockDataStore = mockDataStore2;
setMockDataStore = setMockDataStore2;
the easy way around this is to create store type object of just empty values until the real values come, but that just seems lame :
const mockData: StoreType = {
companyName: 'Test Company',
date: new Date(),
selectType: 'Grocery',
address: {
addressLine1: '123 Test Street',
},
};
const [mockDataStore, setMockDataStore] = createStore<StoreType | {}>(mockData);
const mockData: StoreType = {
companyName: 'Test Company',
date: new Date(),
selectType: 'Grocery',
address: {
addressLine1: '123 Test Street',
},
};
const [mockDataStore, setMockDataStore] = createStore<StoreType | {}>(mockData);
28 Replies
foolswisdom
foolswisdom•13mo ago
Try
<Show when={'date' in mockDataStore && mockDataStore}>
{mockDataStore => {
// rest of your code here
}}
</Show>
<Show when={'date' in mockDataStore && mockDataStore}>
{mockDataStore => {
// rest of your code here
}}
</Show>
(I used 'date', but any property should work)
Braveheart
Braveheart•13mo ago
its never coming past <show now for me> I also tried this put it always passed <show
No description
Braveheart
Braveheart•13mo ago
{mockDataStore => { just gives me syntax errors I also tried this signal but it always passed <Show when={dataLoaded()}> const [dataLoaded, setDataLoaded] = createSignal(false); and later setDataLoaded(true)
foolswisdom
foolswisdom•13mo ago
I don't know what to tell you because this is syntactically valid 🤷
Braveheart
Braveheart•13mo ago
i bit the bullet and did this
const [mockDataStore, setMockDataStore] = createStore<StoreType>({
companyName: 'Test Company 1',
date: new Date(),
selectType: 'Grocery',
address: {
addressLine1: '123 Test Street',
},
});
const [mockDataStore, setMockDataStore] = createStore<StoreType>({
companyName: 'Test Company 1',
date: new Date(),
selectType: 'Grocery',
address: {
addressLine1: '123 Test Street',
},
});
we do that all over our apps atm
foolswisdom
foolswisdom•13mo ago
okay 🤷
Braveheart
Braveheart•13mo ago
its not a great ad for solid but still prefer 100x to react
foolswisdom
foolswisdom•13mo ago
It works fine for me, don't know what to tell you
Braveheart
Braveheart•13mo ago
got an example?
foolswisdom
foolswisdom•13mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
foolswisdom
foolswisdom•13mo ago
I didn't show it in this example, but inside the callback you can safely access any properties like so mockDataStore().address.addressLine1
Braveheart
Braveheart•13mo ago
No description
Braveheart
Braveheart•13mo ago
ah ok ill try
foolswisdom
foolswisdom•13mo ago
It's a function
Braveheart
Braveheart•13mo ago
No description
foolswisdom
foolswisdom•13mo ago
Well, yes, a Date object is not a string lol So TS will error Try mockDataStore().date.toDateString()
Braveheart
Braveheart•13mo ago
i owe you a coffee
No description
Braveheart
Braveheart•13mo ago
4th time you helped me at least
foolswisdom
foolswisdom•13mo ago
Great! 😂 We solved it No problem
Braveheart
Braveheart•13mo ago
ill pay it back with a youtube vid
foolswisdom
foolswisdom•13mo ago
I'm just usually on my phone and it's difficult to spell everything out
Braveheart
Braveheart•13mo ago
and credit ya
foolswisdom
foolswisdom•13mo ago
And write examples
Braveheart
Braveheart•13mo ago
so <Show when={"date" in mockDataStore && mockDataStore}> is vanilla typescript , or some solid black magic?
foolswisdom
foolswisdom•13mo ago
Okay, so "date" in mockDataStore is just a regular javascript check, does this key ('date') exist in the object? And TS knows that if the property is in the object, then it isn't an empty object, so it must be of type StoreType. Now, when you have an expression "date" in mockDataStore && mockDataStore, the && conditional ensures that the expression only resolves to mockDataStore if the first condition passed, which means TS knows that mockDataStore is of type StoreType. If it doesn't pass, then the whole expression simply evaluates to undefined. That's the JS/TS part 👆 Now, you pass this expression to <Show>'s when={}, and solid checks if it is undefined or not. If it is not undefined, then solid passes the value as a function to the callback. Solid also narrows the type (TS) of the value passed to the callback such that TS knows that the value is of type T, not undefined. There's no magic here, just solid doing some type assertions But solid can only do that in callback form
Braveheart
Braveheart•13mo ago
what should my setters be?
No description
foolswisdom
foolswisdom•13mo ago
Hmm that's very interesting, probably something to do with how the TS types for the setter is defined in solid 🤔 You can do setMockDataStore({companyName: e.currentTarget.value}) and TS won't complain Though if you plan on setting properties separately, you might want to consider using createStore<Partial<StoreType>> Which would mean TS would allow some properties to be set while others are not set Which would also solve this problem
Braveheart
Braveheart•13mo ago
this the only reason I use stores atm) i can't be the first to have the issue with stores any examples of this? this seems to allow single prop updates fine not sure i need anything else how would I use your way to replace this path way? setCompanyDetailsStore('companyDetails', 'companyName', e.currentTarget.value) this works
onChange={(e) => setFormDataStore({ address: { addressLine1: e.currentTarget.value } })}
onChange={(e) => setFormDataStore({ address: { addressLine1: e.currentTarget.value } })}