react-redux
Version:
Official React bindings for Redux
278 lines (255 loc) • 9.14 kB
text/typescript
/* eslint-disable no-unused-vars */
// TODO Ignoring all unused variables for now
import {
ClassAttributes,
Component,
ComponentClass,
ComponentType,
StatelessComponent,
Context,
NamedExoticComponent,
} from 'react'
import { Action, ActionCreator, AnyAction, Dispatch, Store } from 'redux'
// import hoistNonReactStatics = require('hoist-non-react-statics');
import type { NonReactStatics } from 'hoist-non-react-statics'
export type FixTypeLater = any
export type EqualityFn<T> = (a: T | undefined, b: T | undefined) => boolean
/**
* This interface can be augmented by users to add default types for the root state when
* using `react-redux`.
* Use module augmentation to append your own type definition in a your_custom_type.d.ts file.
* https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
*/
// tslint:disable-next-line:no-empty-interface
export interface DefaultRootState {}
export type AnyIfEmpty<T extends object> = keyof T extends never ? any : T
export type RootStateOrAny = AnyIfEmpty<DefaultRootState>
// Omit taken from https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
export type DistributiveOmit<T, K extends keyof T> = T extends unknown
? Omit<T, K>
: never
export interface DispatchProp<A extends Action = AnyAction> {
dispatch: Dispatch<A>
}
export type AdvancedComponentDecorator<TProps, TOwnProps> = (
component: ComponentType<TProps>
) => ComponentType<TOwnProps>
/**
* A property P will be present if:
* - it is present in DecorationTargetProps
*
* Its value will be dependent on the following conditions
* - if property P is present in InjectedProps and its definition extends the definition
* in DecorationTargetProps, then its definition will be that of DecorationTargetProps[P]
* - if property P is not present in InjectedProps then its definition will be that of
* DecorationTargetProps[P]
* - if property P is present in InjectedProps but does not extend the
* DecorationTargetProps[P] definition, its definition will be that of InjectedProps[P]
*/
export type Matching<InjectedProps, DecorationTargetProps> = {
[P in keyof DecorationTargetProps]: P extends keyof InjectedProps
? InjectedProps[P] extends DecorationTargetProps[P]
? DecorationTargetProps[P]
: InjectedProps[P]
: DecorationTargetProps[P]
}
/**
* a property P will be present if :
* - it is present in both DecorationTargetProps and InjectedProps
* - InjectedProps[P] can satisfy DecorationTargetProps[P]
* ie: decorated component can accept more types than decorator is injecting
*
* For decoration, inject props or ownProps are all optionally
* required by the decorated (right hand side) component.
* But any property required by the decorated component must be satisfied by the injected property.
*/
export type Shared<InjectedProps, DecorationTargetProps> = {
[P in Extract<
keyof InjectedProps,
keyof DecorationTargetProps
>]?: InjectedProps[P] extends DecorationTargetProps[P]
? DecorationTargetProps[P]
: never
}
// Infers prop type from component C
export type GetProps<C> = C extends ComponentType<infer P>
? C extends ComponentClass<P>
? ClassAttributes<InstanceType<C>> & P
: P
: never
// Applies LibraryManagedAttributes (proper handling of defaultProps
// and propTypes), as well as defines WrappedComponent.
export type ConnectedComponent<
C extends ComponentType<any>,
P
> = ComponentType<P> &
NonReactStatics<C> & {
WrappedComponent: C
}
// Injects props and removes them from the prop requirements.
// Will not pass through the injected props if they are passed in during
// render. Also adds new prop requirements from TNeedsProps.
// Uses distributive omit to preserve discriminated unions part of original prop type
export type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> = <
C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>
>(
component: C
) => ConnectedComponent<
C,
DistributiveOmit<GetProps<C>, keyof Shared<TInjectedProps, GetProps<C>>> &
TNeedsProps
>
// Injects props and removes them from the prop requirements.
// Will not pass through the injected props if they are passed in during
// render.
export type InferableComponentEnhancer<TInjectedProps> =
InferableComponentEnhancerWithProps<TInjectedProps, {}>
export type InferThunkActionCreatorType<
TActionCreator extends (...args: any[]) => any
> = TActionCreator extends (
...args: infer TParams
) => (...args: any[]) => infer TReturn
? (...args: TParams) => TReturn
: TActionCreator
export type HandleThunkActionCreator<TActionCreator> = TActionCreator extends (
...args: any[]
) => any
? InferThunkActionCreatorType<TActionCreator>
: TActionCreator
// redux-thunk middleware returns thunk's return value from dispatch call
// https://github.com/reduxjs/redux-thunk#composition
export type ResolveThunks<TDispatchProps> = TDispatchProps extends {
[key: string]: any
}
? {
[C in keyof TDispatchProps]: HandleThunkActionCreator<TDispatchProps[C]>
}
: TDispatchProps
// the conditional type is to support TypeScript 3.0, which does not support mapping over tuples and arrays;
// once the typings are updated to at least TypeScript 3.1, a simple mapped type can replace this mess
export type ResolveArrayThunks<TDispatchProps extends ReadonlyArray<any>> =
TDispatchProps extends [
infer A1,
infer A2,
infer A3,
infer A4,
infer A5,
infer A6,
infer A7,
infer A8,
infer A9
]
? [
HandleThunkActionCreator<A1>,
HandleThunkActionCreator<A2>,
HandleThunkActionCreator<A3>,
HandleThunkActionCreator<A4>,
HandleThunkActionCreator<A5>,
HandleThunkActionCreator<A6>,
HandleThunkActionCreator<A7>,
HandleThunkActionCreator<A8>,
HandleThunkActionCreator<A9>
]
: TDispatchProps extends [
infer A1,
infer A2,
infer A3,
infer A4,
infer A5,
infer A6,
infer A7,
infer A8
]
? [
HandleThunkActionCreator<A1>,
HandleThunkActionCreator<A2>,
HandleThunkActionCreator<A3>,
HandleThunkActionCreator<A4>,
HandleThunkActionCreator<A5>,
HandleThunkActionCreator<A6>,
HandleThunkActionCreator<A7>,
HandleThunkActionCreator<A8>
]
: TDispatchProps extends [
infer A1,
infer A2,
infer A3,
infer A4,
infer A5,
infer A6,
infer A7
]
? [
HandleThunkActionCreator<A1>,
HandleThunkActionCreator<A2>,
HandleThunkActionCreator<A3>,
HandleThunkActionCreator<A4>,
HandleThunkActionCreator<A5>,
HandleThunkActionCreator<A6>,
HandleThunkActionCreator<A7>
]
: TDispatchProps extends [
infer A1,
infer A2,
infer A3,
infer A4,
infer A5,
infer A6
]
? [
HandleThunkActionCreator<A1>,
HandleThunkActionCreator<A2>,
HandleThunkActionCreator<A3>,
HandleThunkActionCreator<A4>,
HandleThunkActionCreator<A5>,
HandleThunkActionCreator<A6>
]
: TDispatchProps extends [infer A1, infer A2, infer A3, infer A4, infer A5]
? [
HandleThunkActionCreator<A1>,
HandleThunkActionCreator<A2>,
HandleThunkActionCreator<A3>,
HandleThunkActionCreator<A4>,
HandleThunkActionCreator<A5>
]
: TDispatchProps extends [infer A1, infer A2, infer A3, infer A4]
? [
HandleThunkActionCreator<A1>,
HandleThunkActionCreator<A2>,
HandleThunkActionCreator<A3>,
HandleThunkActionCreator<A4>
]
: TDispatchProps extends [infer A1, infer A2, infer A3]
? [
HandleThunkActionCreator<A1>,
HandleThunkActionCreator<A2>,
HandleThunkActionCreator<A3>
]
: TDispatchProps extends [infer A1, infer A2]
? [HandleThunkActionCreator<A1>, HandleThunkActionCreator<A2>]
: TDispatchProps extends [infer A1]
? [HandleThunkActionCreator<A1>]
: TDispatchProps extends Array<infer A>
? Array<HandleThunkActionCreator<A>>
: TDispatchProps extends ReadonlyArray<infer A>
? ReadonlyArray<HandleThunkActionCreator<A>>
: never
/**
* This interface allows you to easily create a hook that is properly typed for your
* store's root state.
*
* @example
*
* interface RootState {
* property: string;
* }
*
* const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
*/
export interface TypedUseSelectorHook<TState> {
<TSelected>(
selector: (state: TState) => TSelected,
equalityFn?: EqualityFn<TSelected>
): TSelected
}