Type loss in `createSelector` with inline function declarations passed as separate arguments
Overview
When using createSelector from Reselect, I've encountered a rare edge case affecting TypeScript type inference. This issue arises specifically when passing input selectors as separate inline arguments composed of inline function declarations.
Detailed Behavior
- ✔️ Working Scenario 1: Input selectors as inline function declarations in a single array works fine.
-
✔️ Working Scenario 2: Input selectors as function declarations passed as separate arguments, defined outside of
createSelectorworks fine. -
❌ Problematic Scenario: Inline function declarations as separate arguments in
createSelectorcause TypeScript to resolve the parameter types of the result function tounknown.
Reproduction
Here are the different scenarios for clarity:
✔️ Scenario 1 - Works Fine:
const selectTodoIds = createSelector(
[
function selectTodos(state: RootState) {
return state.todos;
},
function selectId(state: RootState, id: number) {
return id;
},
],
(todos, id) => todos.map(todo => todo.id)
);
✔️ Scenario 2 - Works Fine:
function selectTodos(state: RootState) {
return state.todos;
}
function selectId(state: RootState, id: number) {
return id;
}
const selectTodoIds = createSelector(selectTodos, selectId, (todos, id) =>
todos.map(todo => todo.id)
);
❌ Problematic Scenario - Result Function Loses its Types:
const selectTodoIds = createSelector(
function selectTodos(state: RootState) {
return state.todos;
},
function selectId(state: RootState, id: number) {
return id;
},
(todos, id) => todos.map(todo => todo.id)
// ❌ Here, both `todos` and `id` resolve to a type of `unknown`.
);
Impact
Although this situation may not happen very often and this issue may not be common, it's important to document for those who might encounter it.
Workarounds
Several simple workarounds include:
- Using arrow functions instead of inline function declarations.
- Grouping input selectors into a single array.
- Defining the function declarations outside of
createSelector.
Either one of these methods solves the problem.
Conclusion
This might be one of those issues that might eventually just go away as TypeScript gets better, but documenting it with potential workarounds can assist others potentially facing similar challenges.
This also is affected when you have a selector "factory" function.
Here is an example ts playground link.
It is a shame this inference doesn't work, hopefully this can be something that can be fixed! Thanks for all the work on this project so far, I use it all the time.
This also is affected when you have a selector "factory" function.
Here is an example ts playground link.
It is a shame this inference doesn't work, hopefully this can be something that can be fixed! Thanks for all the work on this project so far, I use it all the time.
Yeah this is probably one of the weirder issues I've come across when working with TypeScript, I will take another look as soon as I get a chance.
@aryaemami59 thanks for the reply! I also commented here, which may more accurately describe the issue (but could be the same root cause)?
I provide more examples there.
No need to bang your head against the wall on this, there are definitely good work arounds (passing in generics explicitly, assigning the selector to a variable first, using array syntax), so no worries if this doesn't get addressed.
Again, great library, we use it all the time in our app. Thanks!
@aryaemami59 thanks for the reply! I also commented here, which may more accurately describe the issue (but could be the same root cause)?
I provide more examples there.
No need to bang your head against the wall on this, there are definitely good work arounds (passing in generics explicitly, assigning the selector to a variable first, using array syntax), so no worries if this doesn't get addressed.
Again, great library, we use it all the time in our app. Thanks!
Thanks. I appreciate it, it does bother me that this issue exists because we (mostly the maintainers) worked some long hours to make sure the types work, I'll look at it soon and who knows maybe We can find a solution. Thanks again and I will make sure to keep you posted.