typescriptreact-reduxtypescript-typingsredux-toolkitreselect

How to define a version of createSelector typed for my app?


In redux-toolkit docs they suggest you to create the following definition to have proper types when you use useSelector hook:

export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

This will save you of having to type all the selectors with the root state.

However, when it's time to define memoized selector with createSelector there are no instructions about how to do a similar thing. Is there any shortcut for this or I have to manually type every memoized selector?


Solution

  • I was working on a app that I wanted to do the same. For my needs, I just wanted a simple selector, so I did this:

    // store.ts
    
    // …omitted store configuration
    
    export type RootState = ReturnType<typeof store.getState>;
    
    // create a generic type called AppSelector
    export type AppSelector<Return> = (state: RootState) => Return
    // create a custom `createSelector` that uses the type above
    export const createAppSelector = <R>(selector: AppSelector<R>): AppSelector<R> => selector
    

    With the types above, we can do the following:

    const selectTitle: AppSelector<string> = (state) => state.title;
    // Note that using the AppSelector type requires you to always pass the return type argument
    // It's much easier to use the createAppSelector function
    // selectTitle and selectTitle2 accomplish the same thing
    const selectTitle2 = createAppSelector((state) => state.title);
    

    When inside createAppSelector, state will correctly have the RootState type.

    The limitation of this form is that, unlike createSelector, createAppSelector only allows you to create a single selector and doesn't allow you to combine or mutate the selections.

    Hopefully someday we'll have a way to const createAppSelector: TypedCreateSelector<RootState> = createSelector;