From 553aeb5693c1bf986f32dbee505cf97282cdd25a Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 5 Jul 2021 23:36:20 +0000 Subject: [PATCH] Add first version of types for useSelector hook --- src/hooks/{useSelector.js => useSelector.ts} | 41 ++++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) rename src/hooks/{useSelector.js => useSelector.ts} (77%) diff --git a/src/hooks/useSelector.js b/src/hooks/useSelector.ts similarity index 77% rename from src/hooks/useSelector.js rename to src/hooks/useSelector.ts index 85e85d13e..6354873b2 100644 --- a/src/hooks/useSelector.js +++ b/src/hooks/useSelector.ts @@ -3,15 +3,21 @@ import { useReduxContext as useDefaultReduxContext } from './useReduxContext' import Subscription from '../utils/Subscription' import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect' import { ReactReduxContext } from '../components/Context' +import { AnyAction, Store } from 'redux' +import { DefaultRootState } from '../types' -const refEquality = (a, b) => a === b +type EqualityFn = (a: T | undefined, b: T | undefined) => boolean; -function useSelectorWithStoreAndSubscription( - selector, - equalityFn, - store, - contextSub -) { +const refEquality: EqualityFn = (a, b) => a === b + +type TSelector = (state: S) => R; + +function useSelectorWithStoreAndSubscription( + selector: TSelector, + equalityFn: EqualityFn, + store: Store, + contextSub: Subscription +): TSelectedState { const [, forceRender] = useReducer((s) => s + 1, 0) const subscription = useMemo(() => new Subscription(store, contextSub), [ @@ -19,13 +25,13 @@ function useSelectorWithStoreAndSubscription( contextSub, ]) - const latestSubscriptionCallbackError = useRef() - const latestSelector = useRef() - const latestStoreState = useRef() - const latestSelectedState = useRef() + const latestSubscriptionCallbackError = useRef() + const latestSelector = useRef>() + const latestStoreState = useRef() + const latestSelectedState = useRef() const storeState = store.getState() - let selectedState + let selectedState: TSelectedState | undefined try { if ( @@ -65,7 +71,7 @@ function useSelectorWithStoreAndSubscription( function checkForUpdates() { try { const newStoreState = store.getState() - const newSelectedState = latestSelector.current(newStoreState) + const newSelectedState = latestSelector.current!(newStoreState) if (equalityFn(newSelectedState, latestSelectedState.current)) { return @@ -92,7 +98,7 @@ function useSelectorWithStoreAndSubscription( return () => subscription.tryUnsubscribe() }, [store, subscription]) - return selectedState + return selectedState! } /** @@ -101,12 +107,13 @@ function useSelectorWithStoreAndSubscription( * @param {React.Context} [context=ReactReduxContext] Context passed to your ``. * @returns {Function} A `useSelector` hook bound to the specified context. */ -export function createSelectorHook(context = ReactReduxContext) { +export function createSelectorHook(context = ReactReduxContext): (selector: (state: TState) => Selected, equalityFn?: EqualityFn) => Selected { const useReduxContext = context === ReactReduxContext ? useDefaultReduxContext : () => useContext(context) - return function useSelector(selector, equalityFn = refEquality) { + + return function useSelector(selector: (state: TState) => Selected, equalityFn: EqualityFn = refEquality): Selected { if (process.env.NODE_ENV !== 'production') { if (!selector) { throw new Error(`You must pass a selector to useSelector`) @@ -120,7 +127,7 @@ export function createSelectorHook(context = ReactReduxContext) { ) } } - const { store, subscription: contextSub } = useReduxContext() + const { store, subscription: contextSub } = useReduxContext()! const selectedState = useSelectorWithStoreAndSubscription( selector,