In one of my projects, I am using SvelteKit, Tailwind CSS, and especially TypeScript.
During the development, I understood that I must use a writable store, instead of passing the props.
Everything works fine, but the typing system is not as dynamic as it should be.
Let me explain,
To make you understand, where I want to go,
By oversimplifying my actual scenario:
I have an array with child objects with the same shape, like this:
[
{
id: "myUniqueId",
type: "MyType",
properties: {
foo: "bar",
},
},
{
...
},
{
...
},
];
this array is passed inside the writable store like this:
import { writable } from "svelte/store";
import { exampleArray } from "$lib/data/exampleData";
export const myAppStore = writable<TypeMyAppStore>([]);
myAppStore.set(exampleArray);
with this code, everything is right, even in typescript
but, now I want to make the user to explicitly,
to don't add the id
, so the object becomes something like this:
{
type: "MyType",
properties: {
foo: "bar",
},
},
the id
will be added dynamically using .set()
and .update()
appStore.subscribe((value) => {
value.forEach((thisObj) => {
thisObj.id = generateUniqueId();
});
appStore.set(value);
});
with this approach, I can basically add the IDs dynamically when the user pushes a new object inside my store.
the problem is in the IntelliSense autocompletion and typescript, because:
id
the code and app is running fine,
but I need a way to make the writable store, accept only type without id, but in intellisense suggest the id
.
if you think about it, we can say that:
id
,id
.if we want to talk about the same situation but in another context, is like this:
function foo(input: TypeMyInput): TypeMyOuput {}
//This is literally what I want to implement in my svelte store,
//Accept one input with a certain type
// change that array using `.subscribe()`/`.set()`
// then make by svelte store, to think about another type (and not give errors anymore only if the type is not respected, and also give me autocompletion and intellisense)
//For now I solved only the input, but the output not.
// writable<TypeMyInput>([])
How we can do both (I mean without union type) in a way that can accept only one type, but return another type?
all the code above is not nearly my real-world code, is an oversimplified example for you.
Remember
I hope you understand my situation.
if you still don't understand what I want, I can give you the link to my GitHub repo https://github.com/Laaouatni/laaCAD/blob/development/app/src/lib/Data/appStore/appStore.ts
You might want to look at custom stores these allow you to create your own stores (that you can subscribe to with $
) while adding some extra functionality.
For example this code
import { writable } from 'svelte/store';
const createStore = <T extends { id: string }>() => {
const store = writable<T[]>([]);
return {
subscribe: store.subscribe,
add: (value: Exclude<T, 'id'>) => {
const value_with_id = {
...value,
id: crypto.randomUUID() as string
};
store.update(($store) => {
$store.push(value_with_id);
return $store;
});
}
};
};
export default createStore;
does almost what you want:
id
I made it with an add
function just because it feels weird that everytime you change the store you would change all ids ? (I wonder if this wouldn't also cause an infinite loop for that matter because you are changing all items everything an item changes?)
You also ask for a setter
without id, but then use .set
with values that have an id, which seems a bit strange :)