How to type store with generic data #2566
-
|
Hi, I've been trying to get the typings correct for a store where the properties are based on a generic object passed as an argument but I'm having trouble getting typescript to understand what I am looking to do. Basically, I have a store whose value is based on a generic, such that the store has some basic functions provided to manipulate the store, but it also stores the data itself. The code looks like this currently: Given both the 'setValue' and 'setValues' functions, is there a way to type things correctly so that I can stop using ts-ignore? Everything works as expected when using either of these, but I'd like to try to understand what I'm doing wrong so I can extend some of the types further. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
|
It seems like you are facing a tricky situation. Zustand types are somewhat optimized for some use cases which may conflict with generics use case. Anyway, I hope this helps. |
Beta Was this translation helpful? Give feedback.
-
|
I know it's been almost a year since you asked this, but I needed this too, so I made a zustand store which stores a I did it like this: import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
type TFilterParams = {
fromDate: string;
toDate: string;
scoreFilter?: TMemberCareScoreFilterLabelFE;
searchText: string;
searchBy: TMemberCareSearchByLabelFE;
}
type TPartialFilterParams = Partial<TFilterParams> | undefined | null;
type TFilterSortStoreState = {
filter: TPartialFilterParams;
setFilter: (filter: TPartialFilterParams) => void;
resetFilter: () => void;
};
const initialState = {
filterKeyStore: null,
};
type TFilterSortKeyStoreState = {
filterKeyStore: Record<string, { filter?: TPartialFilterParams }> | undefined | null;
setFilter: (key: string) => (filter: TPartialFilterParams) => void;
resetFilter: (key: string) => () => void;
reset: () => void; // resets the entire store (e.g. on user logout)
};
export const useTrueGenericFilterSortStore = create<TFilterSortKeyStoreState>()(
subscribeWithSelector((set) => ({
...initialState,
setFilter: (key) => (newFilter) => {
set((state) => {
return {
...state,
filterKeyStore: {
...state.filterKeyStore,
[key]: { ...state.filterKeyStore?.[key], filter: { ...state.filterKeyStore?.[key]?.filter, ...newFilter } },
},
};
});
},
resetFilter: (key) => () => {
set((state) => ({
...state,
filterKeyStore: { ...state.filterKeyStore, [key]: { ...state.filterKeyStore?.[key], filter: null } },
}));
},
reset: () => {
set((state) => ({
...state,
...initialState,
}));
},
})),
);
export const useGenericFilterStore = (storeKey: string): TFilterSortStoreState => {
const trueGenericStore = useTrueGenericFilterSortStore();
return {
filter: trueGenericStore.filterKeyStore?.[storeKey]?.filter,
setFilter: trueGenericStore.setFilter(storeKey),
resetFilter: trueGenericStore.resetFilter(storeKey),
};
};And I use it in my components like this: const {
filter: filterInStore,
setFilter: setFilterInStore,
} = useGenericFilterStore('some-unique-key'); |
Beta Was this translation helpful? Give feedback.
It seems like you are facing a tricky situation. Zustand types are somewhat optimized for some use cases which may conflict with generics use case.
The easiest way would be
as any, because your types are stricter than what Zustand infers.Anyway, I hope this helps.
https://tsplay.dev/NB6OgN