Assign correct types to Reselect createSelector function

10,502

I might be wrong, but from this this issue, it seems to be caused by how the language infers your heterogenous array [getGroups, getQuestionnaires] as an array and not a tuple.

Forcing the first argument to tuple type will make it work but causes unnecessary boilerplate

const getGroups:Selector<IState, IGroup[]> = state => state.groups;
const getQuestionnaires:Selector<IState, IQuestionnaire[]> = state => 
  state.questionnaires;

const selectors: [Selector<IState, IGroup[]>, Selector<IState, IQuestionnaire[]>] = [getGroups, getQuestionnaires]

export const groups = createSelector<IState, IGroup[], IQuestionnaire[], IGroupReselect>(
  selectors,
  (g, q) => {

    return g.map(group => Object.assign(
      {},
      group,
      {questionnaires: group.questionnairesIds.map(id => q.find(q => q.id === id))}
    ));
  }
);
Share:
10,502
Tristan Hamel
Author by

Tristan Hamel

Experienced Frontend Web Developer with a demonstrated history of working in the computer software industry. Skilled in Angular, AngularJS, Redux, SASS, Github, Node.js, jQuery, and RESTful WebServices. Strong communication and interpersonal skills with atypical educational background focused on arts and social science.

Updated on June 27, 2022

Comments

  • Tristan Hamel
    Tristan Hamel almost 2 years

    Edit: added package.json excerpt

    I am trying to implement typescript in an existing React project and I am facing difficulties with Reselect library. Typescript compiler insists on importing the first definition of createSelector function and fails recognize that my function's signature corresponds to another definition.

    The definition it imports:

    export function createSelector<S, R1, T>(
      selector: Selector<S, R1>,
      combiner: (res: R1) => T,
    ): OutputSelector<S, T, (res: R1) => T>;
    

    The one I want to use:

    export function createSelector<S, R1, R2, T>(
      selectors: [Selector<S, R1>,
                  Selector<S, R2>],
      combiner: (res1: R1, res2: R2) => T,
    ): OutputSelector<S, T, (res1: R1, res2: R2) => T>;
    

    Here is my actual code:

    // groups.selectors.tsx
    
    import { Selector, createSelector } from 'Reselect';
    import { IGroup, IQuestionnaire, IGroupReselect, IState } from '../interfaces';
    
    const getGroups:Selector<IState, IGroup[]> = state => state.groups;
    const getQuestionnaires:Selector<IState, IQuestionnaire[]> = state => state.questionnaires;
    
    export const groups = createSelector<IState, IGroup[], IQuestionnaire[], IGroupReselect>(
      [getGroups, getQuestionnaires],
      (g, q) => {
    
        return g.map(group => Object.assign(
          {},
          group,
          {questionnaires: group.questionnairesIds.map(id => q.find(q => q.id === id))}
        ));
      }
    );
    

    And in case it my be of any help, here is my ts.config:

    {
      "compilerOptions": {
        "module": "es6",
        "target": "es6",
        "outDir": ".temp",
        "allowSyntheticDefaultImports": true,
        "baseUrl": "src",
        "noImplicitAny": false,
        "sourceMap": false,
        "jsx": "preserve",
        "strict": true,
        "moduleResolution": "node"
      },
      "exclude": [
        "node_modules"
      ],
      "files": [
        "typings.d.ts"
      ]
    }
    

    I am not completely comfortable with TypeScript so there is certainly something wrong in my implementation. What bugs me is that if I write the simplest possible reselector, that is one with only 1 selector and a combiner of arity 1, it passes type checking which gives me the impression that the compiler does not properly pick the correct definition among overloaded functions in Reselect's index.d.ts

    Here are relevant parts of my package.json:

    "dependencies": {
        "react": "^15.5.4",
        "react-dom": "^15.5.4",
        "react-redux": "^5.0.5",
        "react-router": "^4.1.1",
        "react-router-dom": "^4.1.1",
        "redux": "^3.6.0",
        "redux-devtools-extension": "^2.13.2",
        "redux-thunk": "^2.2.0",
        "reselect": "^3.0.1"
      },
      "devDependencies": {
        "@types/react": "^15.0.25",
        "@types/react-router-dom": "^4.0.4",
        "@types/redux-thunk": "^2.1.0",
        "typescript": "^2.3.3"
      },