Last active
May 27, 2020 14:00
-
-
Save brunolemos/ff75131ec8887f2035f2e9eb121bba5e to your computer and use it in GitHub Desktop.
Redux + TypeScript - Strongly Typed
This file contains hidden or 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 { GitHubUser } from '../../types' | |
import { createAction, createErrorAction } from '../../utils/helpers/redux' | |
export function loginRequest(payload: { token: string }) { | |
return createAction('LOGIN_REQUEST', payload) | |
} | |
export function loginSuccess(user: GitHubUser) { | |
return createAction('LOGIN_SUCCESS', user) | |
} | |
export function loginFailure<E extends Error>(error: E) { | |
return createErrorAction('LOGIN_FAILURE', error) | |
} | |
export function logout() { | |
return createAction('LOGOUT') | |
} |
This file contains hidden or 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 { User, Reducer } from '../../types' | |
export interface State { | |
token: string | |
user: User | null | |
} | |
const initialState: State = { | |
token: '', | |
user: null, | |
} | |
export const authReducer: Reducer<State> = (state = initialState, action) => { | |
switch (action.type) { | |
// ... | |
case 'LOGIN_SUCCESS': | |
return { | |
user: action.payload, | |
} | |
default: | |
return state | |
} | |
} |
This file contains hidden or 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 React from 'react' | |
import { Button, Text, View } from 'react-native' | |
import { useDispatch } from 'react-redux' | |
import { useReduxState } from '../hooks/use-redux-state' | |
import * as actions from '../redux/actions' | |
import * as selectors from '../redux/selectors' | |
export function LoginScreen() { | |
const dispatch = useDispatch() | |
const user = useReduxState(selectors.currentUserSelector) | |
return ( | |
<View> | |
{user ? ( | |
<> | |
<Text children="Logged" /> | |
<Button onPress={() => dispatch(logout())} title="Logout" /> | |
</> | |
) : ( | |
<> | |
<Button onPress={() => dispatch(login({ token: '123' }))} title="login" /> | |
</> | |
)} | |
</View> | |
) | |
} |
This file contains hidden or 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 { InferableComponentEnhancerWithProps } from 'react-redux' | |
import { Action as ReduxAction, Reducer as ReduxReducer, Dispatch, MiddlewareAPI } from 'redux' | |
import * as actions from '../actions' | |
import { rootReducer } from '../reducers' | |
export interface Action<T extends string, P> extends ReduxAction<T> { | |
payload: P | |
} | |
export interface ActionWithError< | |
T extends string, | |
P, | |
E extends object = Record<string, any> | |
> extends Action<T, P> { | |
payload: P | |
error: E | |
} | |
export type ExtractPayloadFromActionCreator<AC> = AC extends () => any | |
? void | |
: (AC extends (payload: infer P) => any ? P : never) | |
export type ExtractDispatcherFromActionCreator< | |
AC | |
> = ExtractPayloadFromActionCreator<AC> extends void | |
? () => void | |
: (payload: ExtractPayloadFromActionCreator<AC>) => void | |
export type ExtractActionFromActionCreator<AC> = AC extends () => infer A | |
? A | |
: (AC extends (payload: any) => infer A | |
? A | |
: AC extends (payload: any, error: any) => infer A | |
? A | |
: never) | |
export type ExtractPropsFromConnector< | |
Connector | |
> = Connector extends InferableComponentEnhancerWithProps<infer T, any> | |
? T | |
: never | |
export type ExtractStateFromReducer<R> = R extends ReduxReducer<infer S> | |
? S | |
: never | |
export type AllActions = ExtractActionFromActionCreator< | |
typeof actions[keyof typeof actions] | |
> | |
export type Reducer<S = any> = (state: S | undefined, action: AllActions) => S | |
export type RootState = ExtractStateFromReducer<typeof rootReducer> | |
export type Middleware = ( | |
store: MiddlewareAPI, | |
) => (next: Dispatch<AllActions>) => (action: AllActions) => any |
This file contains hidden or 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 { Action, ActionWithError } from '../types' | |
export function createAction<T extends string>(type: T): Action<T, void> | |
export function createAction<T extends string, P>( | |
type: T, | |
payload: P, | |
): Action<T, P> | |
export function createAction<T extends string, P>(type: T, payload?: P) { | |
return typeof payload === 'undefined' ? { type } : { type, payload } | |
} | |
export function createErrorAction<T extends string, E extends object>( | |
type: T, | |
error: E, | |
): ActionWithError<T, void, E> | |
export function createErrorAction< | |
T extends string, | |
E extends object = Record<string, any> | |
>(type: T, error: E) { | |
return { type, error } | |
} | |
export function createErrorActionWithPayload< | |
T extends string, | |
P, | |
E extends object | |
>(type: T, payload: P, error: E): ActionWithError<T, P, E> | |
export function createErrorActionWithPayload< | |
T extends string, | |
P, | |
E extends object = Record<string, any> | |
>(type: T, payload: P, error: E) { | |
return { type, payload, error } | |
} |
This file contains hidden or 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
// NOT NECESSARY ANYMORE SINCE useDispatch WAS OFFICIALLY INTRODUCED | |
import { useMemo } from 'react' | |
import { useDispatch } from 'react-redux' | |
type ActionCreator = (...args: any) => any | |
export function useReduxAction<AC extends ActionCreator>(actionCreator: AC) { | |
const dispatch = useDispatch() | |
return useMemo( | |
() => ( | |
...args: AC extends ((...args: infer Args) => any) ? Args : any[] | |
) => { | |
dispatch(actionCreator(...(args as any[]))) | |
}, | |
[actionCreator], | |
) | |
} |
This file contains hidden or 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 _ from 'lodash' | |
import { useSelector } from 'react-redux' | |
type Result<S> = S extends (...args: any[]) => infer R ? R : any | |
export function useReduxState< | |
S extends (state: any) => any, | |
R extends Result<S> | |
>(selector: S, equalityFn?: (left: R, right: R) => boolean) { | |
return useSelector(selector, equalityFn) as R | |
} |
This looks really good. Is there a complete example of the code? I think i miss some files :)
Trying to learn react/redux with typescript.
@Liteolika I think all files are in this gist, maybe with the wrong import, but you can check them on this project: https://github.com/devhubapp/devhub/tree/master/packages/components/src/redux
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@brunolemas
no meu redux o nome do tipo eh so
Reducer
naoReduxReducer
:)