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 1 reply
-
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