Skip to content

Instantly share code, notes, and snippets.

@ferdaber
Created February 9, 2019 02:02
Show Gist options
  • Select an option

  • Save ferdaber/eb4bd09ad88f65fa89ac7f7ff92fe341 to your computer and use it in GitHub Desktop.

Select an option

Save ferdaber/eb4bd09ad88f65fa89ac7f7ff92fe341 to your computer and use it in GitHub Desktop.
strongly-typed-redux-2
type State = any
/**
* General action type
*/
export type Action<TType extends string = string, TPayload = any> = TPayload extends undefined
? {
type: TType
}
: {
type: TType
payload: TPayload
}
/**
* A type of action that is actually dispatched after the promise middleware
* modifies it if it has a promise-based payload
*/
export interface PromiseAction<TAction extends Action<any, Promise<any>>> {
status: string
payload: any
type: TAction['type']
promise: TAction['payload']
}
/**
* The type of a dispatched action when it has a promise as a payload
* This one is immediately dispatched after going through the middleware
*/
export interface PendingPromiseAction<TAction extends Action<any, Promise<any>>>
extends PromiseAction<TAction> {
status: 'pending'
payload: TAction['payload']
}
/**
* The type of a dispatched action when it has a promise as a payload
* This one is dispatched when the promise is fulfilled
*/
export interface FulfilledPromiseAction<TAction extends Action<any, Promise<any>>>
extends PromiseAction<TAction> {
status: 'fulfilled'
payload: PromiseValue<TAction['payload']>
}
/**
* The type of a dispatched action when it has a promise as a payload
* This one is dispatched when the promise is rejected
*/
export interface RejectedPromiseAction<TAction extends Action<any, Promise<any>>>
extends PromiseAction<TAction> {
status: 'rejected'
payload: Error
}
/**
* Types of actions created from an action creator, mainly if it's a promise-based
* action it can potentially dispatch three actions based on how the promise resolves
*/
export type PossibleActions<TActionCreator extends ActionCreator> = TActionCreator extends any
? ReturnType<TActionCreator> extends { payload: Promise<any> }
?
| PendingPromiseAction<ReturnType<TActionCreator>>
| FulfilledPromiseAction<ReturnType<TActionCreator>>
| RejectedPromiseAction<ReturnType<TActionCreator>>
: ReturnType<TActionCreator>
: never
/**
* General action creator type
*/
export interface ActionCreator<
TType extends string = string,
TPayload = any,
TArgs extends any[] = []
> {
(...args: TArgs): Action<TType, TPayload>
type: TType
toString(): TType
}
/**
* Given an actual action object, resolves the return type
* when this action object is dispatched, using thunk and promise middlewares
*/
export type DispatchedAction<TAction> = TAction extends { type: infer TType }
? TType extends string
? TAction extends { payload: Promise<any> }
? PendingPromiseAction<TAction>
: TAction
: never
: TAction extends Thunk<infer TReturn>
? TReturn
: never
/**
* Call signature of the dispatch function, which is more restrictive than the
* DispatchedAction type, but essentially the same, in function form
*/
export interface Dispatch<TState = State> {
<TAction extends Action>(action: TAction): DispatchedAction<TAction>
<TReturn>(thunk: (dispatch: Dispatch<TState>, getState: () => TState) => TReturn): TReturn
}
/**
* Call signature of a thunk, which is passed the dispatch and getState APIs
*/
export interface Thunk<TReturn, TState = State> {
(dispatch: Dispatch<TState>, getState: () => TState): TReturn
}
/**
* A reducer based off of a state slice and an action creator, it can mutate the state
* because of the outer Immer wrapper
*/
export interface Reducer<TState, TActionCreator extends ActionCreator> {
(state: TState, action: PossibleActions<TActionCreator>): void | TState
type: TActionCreator['type']
}
export interface Middleware<TState = State> {
(
store: {
dispatch: Dispatch<TState>
getState(): TState
}
): (next: (action: any) => void) => (action: any) => void
}
export declare function mapDispatchToProps<A extends Records<string, () => any>>(actionCreators: A, dispatch: Dispatch): {
[K in keyof A]: A[K] extends (...args: infer TArgs) => infer TAction ? (...args: TArgs) => DispatchedAction<TAction> : A[K]
}
@ferdaber
Copy link
Copy Markdown
Author

ferdaber commented Feb 9, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment