Newish to Typescript. I and moving a project to TS and I am struggling to define the Typescript for my reducers when creating a slice using redux-toolkit. The scenario is I have filters stored in a state. I have a query string and an object of fields that will be filtered if a value is present. The type of each field depends on the data stored in that field. To set a field filter value I have created a reducer that accepts a key and value pair as the payload. I then use that to set the filter value for that field. After all of my Googling, ChatGPTing and Gemini-ing I am still getting the following error.
Type 'string | string[]' is not assignable to type 'string[] & string'.
Type 'string' is not assignable to type 'string[] & string'.
Type 'string' is not assignable to type 'string[]'.ts(2322)
(property) filters: WritableDraft<FilterValues>
This is the code for the slice. I have tried multiple types for the payload of setFilter and removeFilter and have left two of the setFilters to show what I have tried.
import { PayloadAction, createSelector, createSlice } from '@reduxjs/toolkit';
import { RootState } from "redux/store";
export type FilterValues = {
tags_map: string[];
reference: string;
time_executed: string;
type: string;
}
interface State {
filterQuery: string;
filters: FilterValues;
}
const initialState:State = {
filterQuery: '',
filters: {
tags_map: [],
reference: '',
time_executed: '',
type: '',
},
};
type KeyValuePayload<T> = {
[K in keyof T]: {
key: K;
value: T[K]
}
}[keyof T];
export const slice = createSlice({
name: 'filters',
initialState,
reducers: {
setFilterQuery: (state, { payload }) => {
state.filterQuery = payload
},
// setFilter : (state, { payload }: PayloadAction<{ key: keyof FilterValues, value: FilterValues[keyof FilterValues] }>) => {
// state.filters[payload.key] = payload.value
// },
setFilter : (state, { payload }: PayloadAction<KeyValuePayload<FilterValues>>) => {
const { key, value } = payload
state.filters[key] = value
},
removeFilter: (state, { payload }: PayloadAction<keyof FilterValues>) => {
state.filters[payload] = initialState.filters[payload]
},
removeAllFilters: (state) => {
return { ...state, filters: initialState.filters }
},
},
});
export const {
setFilterQuery,
setFilter,
removeFilter,
removeAllFilters,
} = slice.actions;
export default slice. Reducer;
Sample payload
setFilter({key: "reference", value: "foobar"})
setFilter({key: "tags_map", value: ["foo", "bar"]})
I am at a loss. I used the approach explained in this answer, and trying it in TS playground it infers the correct types. But it I am still getting errors. I am sure there is a simple answer to this.
Thank you in advance.