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"
},
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))}
));
}
);