-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Expand file tree
/
Copy pathtypes.ts
More file actions
180 lines (156 loc) · 5.64 KB
/
types.ts
File metadata and controls
180 lines (156 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import type {
ClassAttributes,
ComponentClass,
ComponentType,
FunctionComponent,
JSX,
} from 'react'
import type { Action, UnknownAction, Dispatch } from 'redux'
import type { NonReactStatics } from './utils/hoistStatics'
import type { ConnectProps } from './components/connect'
import type { UseSelectorOptions } from './hooks/useSelector'
export type FixTypeLater = any
export type EqualityFn<T> = (a: T, b: T) => boolean
export type ExtendedEqualityFn<T, P> = (a: T, b: T, c: P, d: P) => boolean
export type AnyIfEmpty<T extends object> = keyof T extends never ? any : T
export type DistributiveOmit<T, K extends keyof T> = T extends unknown
? Omit<T, K>
: never
export interface DispatchProp<A extends Action<string> = UnknownAction> {
dispatch: Dispatch<A>
}
/**
* 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).
export type GetLibraryManagedProps<C> = JSX.LibraryManagedAttributes<
C,
GetProps<C>
>
// Applies LibraryManagedAttributes (proper handling of defaultProps
// and propTypes), as well as defines WrappedComponent.
export type ConnectedComponent<
C extends ComponentType<any>,
P,
> = FunctionComponent<P> &
NonReactStatics<C> & {
WrappedComponent: C
}
export type ConnectPropsMaybeWithoutContext<TActualOwnProps> =
TActualOwnProps extends { context: any }
? Omit<ConnectProps, 'context'>
: ConnectProps
type Identity<T> = T
export type Mapped<T> = Identity<{ [k in keyof T]: T[k] }>
// 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.
// Note> Most of the time TNeedsProps is empty, because the overloads in `Connect`
// just pass in `{}`. The real props we need come from the component.
export type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> = <
C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>,
>(
component: C,
) => ConnectedComponent<
C,
Mapped<
DistributiveOmit<
GetLibraryManagedProps<C>,
keyof Shared<TInjectedProps, GetLibraryManagedProps<C>>
> &
TNeedsProps &
ConnectPropsMaybeWithoutContext<TNeedsProps & GetProps<C>>
>
>
// 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
/**
* 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<NoInfer<TSelected>>,
): TSelected
<Selected = unknown>(
selector: (state: TState) => Selected,
options?: UseSelectorOptions<Selected>,
): Selected
}
export type NoInfer<T> = [T][T extends any ? 0 : never]