1

I'm having a hard time refactor my reducers to TS since I'm using Immutable.js in my project This is my reducer:

export interface DashboardState {
   componentId: number | null;
   dashboard: number | null;
}

let defaultState: DashboardState = {
   componentId: null,
   dashboard: null,
};

export default function (state = Map<string, number>(defaultState), action):  
Map<string, number> {
    switch (action.type) {
        case dashboardsActionsTypes.SET_PROJECT_VIEW:
            return state.set('componentId', action.payload);
        case dashboardsActionsTypes.SET_DASHBOARD_TYPE:
            return state.set('dashboard', action.payload);
        default:
            return state;
    }
}

I'm getting an error on the Map(defaultState) that says: enter image description here

What I'm missing here?

Thanks

1
  • 1
    Map is a ... map with getter and setters etc, regardless of what data you store in it. I guess your state would have to be defaultState : Immutable.Map<string, any> Commented Apr 6, 2021 at 7:16

1 Answer 1

2

There are multiple ways to construct a Map.

export function Map<K, V>(collection: Iterable<[K, V]>): Map<K, V>;
export function Map<V>(obj: {[key: string]: V}): Map<string, V>;
export function Map<K, V>(): Map<K, V>;
export function Map(): Map<any, any>;

The error on the first overload is expected because you definitely shouldn't match that one. Your object is closer to the second overload, but you don't match that overload automatically because it involves a string index signature which DashboardState does not have.

The quick and dirty solution here involves setting a generic on the Map function. As you can see, the second overload is the only one with just <V> instead of <K, V>. So you can match this overload by setting just a value type for the Map. In this case the value type of DashboardState is any.

state = Map<any>(defaultState)

The type support with this setup is extremely weak. The keys of state can be any string and the values can be absolutely anything. Why bother using Typescript at all if you can't get any useful information out of it?

I recommend using the official Redux Toolkit which has strong typescript support as well as support for immutability using Immer. And replace the any in your DashboardState with the actual types.


Edit:

After viewing your edit, I recommend that you use optional properties (number | undefined) instead of number | null since Map.get() includes undefined along with the expected value. So you would get number | null | undefined. If using optional properties then you don't actually need an initial state at all. You can use an empty Map.

We can also limit the keys to just the keys of DashboardState.

Use these utilities on any state type:

export type MapOf<T> = Map<keyof T, T[keyof T]>;

const createMap = <T,>(): MapOf<T> => Map<keyof T, T[keyof T]>();

For the dashboard:

export interface DashboardState {
  componentId?: number;
  dashboard?: number;
}

export default function (state = createMap<DashboardState>(), action): MapOf<DashboardState> {
   switch (action.type) {
       case dashboardsActionsTypes.SET_PROJECT_VIEW:
           return state.set('componentId', action.payload);
       case dashboardsActionsTypes.SET_DASHBOARD_TYPE:
           return state.set('dashboard', action.payload);
       default:
           return state;
   }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Paist Thanks for the explanations. I updated my code and added types to the default state and typed the Map constructor. I'm not sure I understand how to solve the issue since I'm still getting the same error. Can you write any example so maybe I will understand it better?
export default function (state = Map<number | null>(defaultState), action): Map<string, number | null> and remove the type from defaultState. But you should use undefined instead of null since Map.get() includes undefined. And really you should just use Redux Toolkit :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.