Skip to content

Commit 5082af7

Browse files
authored
Merge pull request #1965 from reduxjs/draft/amazing-rosalind
2 parents ad40b97 + bafe55e commit 5082af7

File tree

4 files changed

+23
-7
lines changed

4 files changed

+23
-7
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Set up Node
2020
uses: actions/setup-node@v2
2121
with:
22-
node-version: 14.x
22+
node-version: 16.x
2323
cache: 'yarn'
2424

2525
- name: Install dependencies
@@ -39,8 +39,8 @@ jobs:
3939
strategy:
4040
fail-fast: false
4141
matrix:
42-
node: ['14.x']
43-
ts: ['4.0', '4.1', '4.2', '4.3', '4.4', '4.5', '4.6', 'next']
42+
node: ['16.x']
43+
ts: ['4.1', '4.2', '4.3', '4.4', '4.5', '4.6', '4.7', '4.8', '4.9.2-rc']
4444
steps:
4545
- name: Checkout repo
4646
uses: actions/checkout@v2

src/hooks/useSelector.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useContext, useDebugValue } from 'react'
22

33
import { useReduxContext as useDefaultReduxContext } from './useReduxContext'
44
import { ReactReduxContext } from '../components/Context'
5-
import type { EqualityFn } from '../types'
5+
import type { EqualityFn, NoInfer } from '../types'
66
import type { uSESWS } from '../utils/useSyncExternalStore'
77
import { notInitialized } from '../utils/useSyncExternalStore'
88

@@ -32,7 +32,7 @@ export function createSelectorHook(
3232

3333
return function useSelector<TState, Selected extends unknown>(
3434
selector: (state: TState) => Selected,
35-
equalityFn: EqualityFn<Selected> = refEquality
35+
equalityFn: EqualityFn<NoInfer<Selected>> = refEquality
3636
): Selected {
3737
if (process.env.NODE_ENV !== 'production') {
3838
if (!selector) {

src/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ export type ResolveThunks<TDispatchProps> = TDispatchProps extends {
165165
export interface TypedUseSelectorHook<TState> {
166166
<TSelected>(
167167
selector: (state: TState) => TSelected,
168-
equalityFn?: EqualityFn<TSelected>
168+
equalityFn?: EqualityFn<NoInfer<TSelected>>
169169
): TSelected
170170
}
171+
172+
export type NoInfer<T> = [T][T extends any ? 0 : never]

test/typetests/hooks.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
fetchCount,
3535
} from './counterApp'
3636

37-
import { expectType } from '../typeTestHelpers'
37+
import { expectType, expectExactType } from '../typeTestHelpers'
3838

3939
function preTypedHooksSetup() {
4040
// Standard hooks setup
@@ -87,6 +87,20 @@ function testShallowEqual() {
8787
shallowEqual({ test: 'test' }, { test: 'test' })
8888
shallowEqual({ test: 'test' }, 'a')
8989
const x: boolean = shallowEqual('a', 'a')
90+
91+
type TestState = { stateProp: string }
92+
93+
// Additionally, it should infer its type from arguments and not become `any`
94+
const selected1 = useSelector(
95+
(state: TestState) => state.stateProp,
96+
shallowEqual
97+
)
98+
expectExactType<string>(selected1)
99+
100+
const useAppSelector: TypedUseSelectorHook<TestState> = useSelector
101+
102+
const selected2 = useAppSelector((state) => state.stateProp, shallowEqual)
103+
expectExactType<string>(selected2)
90104
}
91105

92106
function testUseDispatch() {

0 commit comments

Comments
 (0)