Skip to content

fix(useSelector): add NoInfer to equality fn in UseSelector type (#2186)#2341

Open
veksa wants to merge 1 commit into
reduxjs:masterfrom
veksa:fix/2186-useselector-shallowequal-noinfer
Open

fix(useSelector): add NoInfer to equality fn in UseSelector type (#2186)#2341
veksa wants to merge 1 commit into
reduxjs:masterfrom
veksa:fix/2186-useselector-shallowequal-noinfer

Conversation

@veksa

@veksa veksa commented Jul 20, 2026

Copy link
Copy Markdown

Fixes #2186.

When you pass shallowEqual as the second argument to useSelector (or to a
hook made with useSelector.withTypes<State>()), TypeScript was treating the
equality function as an inference site for the selected value. shallowEqual
is typed with any parameters, so that could collapse the result down to any
instead of the selector's actual return type.

The implementation inside createSelectorHook already wraps this argument in
NoInfer — the public UseSelector interface just never got the same
treatment. So this just brings the two in line:

   <TState extends StateType = StateType, Selected = unknown>(
     selector: (state: TState) => Selected,
-    equalityFnOrOptions?: EqualityFn<Selected> | UseSelectorOptions<Selected>,
+    equalityFnOrOptions?:
+      | EqualityFn<NoInfer<Selected>>
+      | UseSelectorOptions<NoInfer<Selected>>,
   ): Selected

One heads-up: on master with the currently supported TS versions I couldn't
actually reproduce the any result anymore — the existing shallowEqual test
passes, and the new ones pass with or without this change. So really this is
(a) keeping the public type consistent with the implementation, and (b) a
safety net for older/other TS setups where the equality arg can still leak into
inference. If you'd rather just close the issue with the added tests and skip
the type change, I'm happy to drop it.

I also added type tests for the cases from the issue that weren't covered
before: a selector declared as a separate variable (not inline), the same
through plain useSelector, and passing shallowEqual via the options object.

Type-only change, nothing runtime.

@pkg-pr-new

pkg-pr-new Bot commented Jul 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/react-redux@50093eb -D
yarn add https://pkg.pr.new/react-redux@50093eb.tgz -D
pnpm add https://pkg.pr.new/react-redux@50093eb.tgz -D
bun add https://pkg.pr.new/react-redux@50093eb.tgz -D

commit: 50093eb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useSelector doesn't infer selector types properly with shallowEqual

1 participant