Last active
February 29, 2020 02:38
-
-
Save sarimarton/d5d539f8029c01ca1c357aba27139010 to your computer and use it in GitHub Desktop.
Properly typed React-Redux hooks with exact event shape match in dispatch() calls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as RR from 'react-redux' | |
// Exact matcher. This was made by a genius guy... | |
// https://github.com/microsoft/TypeScript/issues/12936#issuecomment-524631270 | |
type ExactInner<T> = <D>() => D extends T ? D : D | |
type Exact<T> = ExactInner<T> & T | |
export function exact<T>(obj: Exact<T> | T): Exact<T> { | |
return obj as Exact<T> | |
} | |
// This is a short getter for precisely typed hooks. The useSelector part is given | |
// in the official React-Redux guide. The useDispatch part is the point here. The | |
// React-Redux guide is not helpful here at all. There is a short version to make it: | |
// export const useDispatch = () => RR.useDispatch<Dispatch<StoreEvent>>() | |
// but it doesn't protect against excess properties in the event objects. | |
// Exact match is hard to do in TS, and the above solution is the only _proper_ | |
// solution which works with unions. It needs an extra runtime invocation though, | |
// so we wrap our helper here | |
export function getTypedHooks<Store, StoreEvent>() { | |
const useSelector: RR.TypedUseSelectorHook<Store> = RR.useSelector | |
const useDispatch = () => { | |
const dispatch = RR.useDispatch() | |
return (event: StoreEvent) => dispatch(exact(event)) | |
} | |
return { useSelector, useDispatch } | |
} | |
// Use it in your store file like this: | |
// | |
// import { getTypedHooks } from 'get-typed-redux-hooks' | |
// | |
// interface Store { ... } | |
// type StoreEvent = | |
// | { type: 'EVENT1' } | |
// | { type: 'EVENT2', data: any } | |
// | |
// export const { useSelector, useDispatch } = getTypedHooks<Store, StoreEvent>() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment