Skip to content

Commit 6272825

Browse files
committed
Make context typing more accurate
1 parent e04515a commit 6272825

16 files changed

+63
-65
lines changed

docs/api/Provider.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ interface ProviderProps<A extends Action = AnyAction, S = any> {
3939
* to create a context to be used.
4040
* If this is used, you'll need to customize `connect` by supplying the same
4141
* context provided to the Provider.
42-
* Initial value doesn't matter, as it is overwritten with the internal state of Provider.
42+
* Set the initial value to null, and the hooks will error
43+
* if this is not overwritten by Provider.
4344
*/
44-
context?: Context<ReactReduxContextValue<S, A>>
45+
context?: Context<ReactReduxContextValue<S, A> | null>
4546

4647
/** Global configuration for the `useSelector` stability check */
4748
stabilityCheck?: StabilityCheck

docs/using-react-redux/accessing-store.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Redux store accessible to deeply nested connected components. As of React Redux
2727
by a single default context object instance generated by `React.createContext()`, called `ReactReduxContext`.
2828

2929
React Redux's `<Provider>` component uses `<ReactReduxContext.Provider>` to put the Redux store and the current store
30-
state into context, and `connect` uses `<ReactReduxContext.Consumer>` to read those values and handle updates.
30+
state into context, and `connect` uses `useContext(ReactReduxContext)` to read those values and handle updates.
3131

3232
## Using the `useStore` Hook
3333

@@ -87,8 +87,8 @@ This also provides a natural isolation of the stores as they live in separate co
8787

8888
```js
8989
// a naive example
90-
const ContextA = React.createContext();
91-
const ContextB = React.createContext();
90+
const ContextA = React.createContext(null);
91+
const ContextB = React.createContext(null);
9292

9393
// assuming reducerA and reducerB are proper reducer functions
9494
const storeA = createStore(reducerA);

src/components/Context.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ export interface ReactReduxContextValue<
1616
}
1717

1818
const ContextKey = Symbol.for(`react-redux-context-${ReactVersion}`)
19-
const gT = globalThis as { [ContextKey]?: Context<ReactReduxContextValue> }
19+
const gT = globalThis as {
20+
[ContextKey]?: Context<ReactReduxContextValue | null>
21+
}
2022

2123
function getContext() {
2224
let realContext = gT[ContextKey]
2325
if (!realContext) {
24-
realContext = createContext<ReactReduxContextValue>(null as any)
26+
realContext = createContext<ReactReduxContextValue | null>(null)
2527
if (process.env.NODE_ENV !== 'production') {
2628
realContext.displayName = 'ReactRedux'
2729
}
@@ -31,8 +33,8 @@ function getContext() {
3133
}
3234

3335
export const ReactReduxContext = /*#__PURE__*/ new Proxy(
34-
{} as Context<ReactReduxContextValue>,
35-
/*#__PURE__*/ new Proxy<ProxyHandler<Context<ReactReduxContextValue>>>(
36+
{} as Context<ReactReduxContextValue | null>,
37+
/*#__PURE__*/ new Proxy<ProxyHandler<Context<ReactReduxContextValue | null>>>(
3638
{},
3739
{
3840
get(_, handler) {

src/components/Provider.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ export interface ProviderProps<A extends Action = AnyAction, S = unknown> {
2121
/**
2222
* Optional context to be used internally in react-redux. Use React.createContext() to create a context to be used.
2323
* If this is used, you'll need to customize `connect` by supplying the same context provided to the Provider.
24-
* Initial value doesn't matter, as it is overwritten with the internal state of Provider.
24+
* Set the initial value to null, and the hooks will error
25+
* if this is not overwritten by Provider.
2526
*/
26-
context?: Context<ReactReduxContextValue<S, A>>
27+
context?: Context<ReactReduxContextValue<S, A> | null>
2728

2829
/** Global configuration for the `useSelector` stability check */
2930
stabilityCheck?: CheckFrequency

src/components/connect.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ function connect<
584584
: contextValue!.store
585585

586586
const getServerState = didStoreComeFromContext
587-
? contextValue.getServerState
587+
? contextValue!.getServerState
588588
: store.getState
589589

590590
const childPropsSelector = useMemo(() => {

src/hooks/useDispatch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function createDispatchHook<
1515
S = unknown,
1616
A extends Action = AnyAction
1717
// @ts-ignore
18-
>(context?: Context<ReactReduxContextValue<S, A>> = ReactReduxContext) {
18+
>(context?: Context<ReactReduxContextValue<S, A> | null> = ReactReduxContext) {
1919
const useStore =
2020
// @ts-ignore
2121
context === ReactReduxContext ? useDefaultStore : createStoreHook(context)

src/hooks/useReduxContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { ReactReduxContextValue } from '../components/Context'
1010
* @returns {Function} A `useReduxContext` hook bound to the specified context.
1111
*/
1212
export function createReduxContextHook(context = ReactReduxContext) {
13-
return function useReduxContext(): ReactReduxContextValue | null {
13+
return function useReduxContext(): ReactReduxContextValue {
1414
const contextValue = useContext(context)
1515

1616
if (process.env.NODE_ENV !== 'production' && !contextValue) {
@@ -19,7 +19,7 @@ export function createReduxContextHook(context = ReactReduxContext) {
1919
)
2020
}
2121

22-
return contextValue
22+
return contextValue!
2323
}
2424
}
2525

src/hooks/useSelector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export function createSelectorHook(context = ReactReduxContext): UseSelector {
8080
getServerState,
8181
stabilityCheck: globalStabilityCheck,
8282
noopCheck: globalNoopCheck,
83-
} = useReduxContext()!
83+
} = useReduxContext()
8484

8585
const firstRun = useRef(true)
8686

src/hooks/useStore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function createStoreHook<
1717
S = unknown,
1818
A extends BasicAction = AnyAction
1919
// @ts-ignore
20-
>(context?: Context<ReactReduxContextValue<S, A>> = ReactReduxContext) {
20+
>(context?: Context<ReactReduxContextValue<S, A> | null> = ReactReduxContext) {
2121
const useReduxContext =
2222
// @ts-ignore
2323
context === ReactReduxContext
@@ -29,7 +29,7 @@ export function createStoreHook<
2929
Action extends BasicAction = A
3030
// @ts-ignore
3131
>() {
32-
const { store } = useReduxContext()!
32+
const { store } = useReduxContext()
3333
// @ts-ignore
3434
return store as Store<State, Action>
3535
}

test/components/connect.spec.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2130,9 +2130,10 @@ describe('React', () => {
21302130
}
21312131
}
21322132

2133-
const context = React.createContext<
2134-
ReactReduxContextValue<any, AnyAction>
2135-
>(null as any)
2133+
const context = React.createContext<ReactReduxContextValue<
2134+
any,
2135+
AnyAction
2136+
> | null>(null)
21362137

21372138
let actualState
21382139

@@ -2171,9 +2172,10 @@ describe('React', () => {
21712172
}
21722173
}
21732174

2174-
const context = React.createContext<
2175-
ReactReduxContextValue<any, AnyAction>
2176-
>(null as any)
2175+
const context = React.createContext<ReactReduxContextValue<
2176+
any,
2177+
AnyAction
2178+
> | null>(null)
21772179

21782180
let actualState
21792181

@@ -2425,9 +2427,8 @@ describe('React', () => {
24252427
(state: RootStateType = 0, action: ActionType) =>
24262428
action.type === 'INC' ? state + 1 : state
24272429
)
2428-
const customContext = React.createContext<ReactReduxContextValue>(
2429-
null as any
2430-
)
2430+
const customContext =
2431+
React.createContext<ReactReduxContextValue | null>(null)
24312432

24322433
class A extends Component {
24332434
render() {

0 commit comments

Comments
 (0)