UNPKG

6.31 kBPlain TextView Raw
1import type { Middleware, StoreEnhancer } from 'redux'
2import type { Tuple } from './utils'
3
4export function safeAssign<T extends object>(
5 target: T,
6 ...args: Array<Partial<NoInfer<T>>>
7) {
8 Object.assign(target, ...args)
9}
10
11/**
12 * return True if T is `any`, otherwise return False
13 * taken from https://github.com/joonhocho/tsdef
14 *
15 * @internal
16 */
17export type IsAny<T, True, False = never> =
18 // test if we are going the left AND right path in the condition
19 true | false extends (T extends never ? true : false) ? True : False
20
21export type CastAny<T, CastTo> = IsAny<T, CastTo, T>
22
23/**
24 * return True if T is `unknown`, otherwise return False
25 * taken from https://github.com/joonhocho/tsdef
26 *
27 * @internal
28 */
29export type IsUnknown<T, True, False = never> = unknown extends T
30 ? IsAny<T, False, True>
31 : False
32
33export type FallbackIfUnknown<T, Fallback> = IsUnknown<T, Fallback, T>
34
35/**
36 * @internal
37 */
38export type IfMaybeUndefined<P, True, False> = [undefined] extends [P]
39 ? True
40 : False
41
42/**
43 * @internal
44 */
45export type IfVoid<P, True, False> = [void] extends [P] ? True : False
46
47/**
48 * @internal
49 */
50export type IsEmptyObj<T, True, False = never> = T extends any
51 ? keyof T extends never
52 ? IsUnknown<T, False, IfMaybeUndefined<T, False, IfVoid<T, False, True>>>
53 : False
54 : never
55
56/**
57 * returns True if TS version is above 3.5, False if below.
58 * uses feature detection to detect TS version >= 3.5
59 * * versions below 3.5 will return `{}` for unresolvable interference
60 * * versions above will return `unknown`
61 *
62 * @internal
63 */
64export type AtLeastTS35<True, False> = [True, False][IsUnknown<
65 ReturnType<<T>() => T>,
66 0,
67 1
68>]
69
70/**
71 * @internal
72 */
73export type IsUnknownOrNonInferrable<T, True, False> = AtLeastTS35<
74 IsUnknown<T, True, False>,
75 IsEmptyObj<T, True, IsUnknown<T, True, False>>
76>
77
78/**
79 * Convert a Union type `(A|B)` to an intersection type `(A&B)`
80 */
81export type UnionToIntersection<U> = (
82 U extends any ? (k: U) => void : never
83) extends (k: infer I) => void
84 ? I
85 : never
86
87// Appears to have a convenient side effect of ignoring `never` even if that's not what you specified
88export type ExcludeFromTuple<T, E, Acc extends unknown[] = []> = T extends [
89 infer Head,
90 ...infer Tail,
91]
92 ? ExcludeFromTuple<Tail, E, [...Acc, ...([Head] extends [E] ? [] : [Head])]>
93 : Acc
94
95type ExtractDispatchFromMiddlewareTuple<
96 MiddlewareTuple extends readonly any[],
97 Acc extends {},
98> = MiddlewareTuple extends [infer Head, ...infer Tail]
99 ? ExtractDispatchFromMiddlewareTuple<
100 Tail,
101 Acc & (Head extends Middleware<infer D> ? IsAny<D, {}, D> : {})
102 >
103 : Acc
104
105export type ExtractDispatchExtensions<M> =
106 M extends Tuple<infer MiddlewareTuple>
107 ? ExtractDispatchFromMiddlewareTuple<MiddlewareTuple, {}>
108 : M extends ReadonlyArray<Middleware>
109 ? ExtractDispatchFromMiddlewareTuple<[...M], {}>
110 : never
111
112type ExtractStoreExtensionsFromEnhancerTuple<
113 EnhancerTuple extends readonly any[],
114 Acc extends {},
115> = EnhancerTuple extends [infer Head, ...infer Tail]
116 ? ExtractStoreExtensionsFromEnhancerTuple<
117 Tail,
118 Acc & (Head extends StoreEnhancer<infer Ext> ? IsAny<Ext, {}, Ext> : {})
119 >
120 : Acc
121
122export type ExtractStoreExtensions<E> =
123 E extends Tuple<infer EnhancerTuple>
124 ? ExtractStoreExtensionsFromEnhancerTuple<EnhancerTuple, {}>
125 : E extends ReadonlyArray<StoreEnhancer>
126 ? UnionToIntersection<
127 E[number] extends StoreEnhancer<infer Ext>
128 ? Ext extends {}
129 ? IsAny<Ext, {}, Ext>
130 : {}
131 : {}
132 >
133 : never
134
135type ExtractStateExtensionsFromEnhancerTuple<
136 EnhancerTuple extends readonly any[],
137 Acc extends {},
138> = EnhancerTuple extends [infer Head, ...infer Tail]
139 ? ExtractStateExtensionsFromEnhancerTuple<
140 Tail,
141 Acc &
142 (Head extends StoreEnhancer<any, infer StateExt>
143 ? IsAny<StateExt, {}, StateExt>
144 : {})
145 >
146 : Acc
147
148export type ExtractStateExtensions<E> =
149 E extends Tuple<infer EnhancerTuple>
150 ? ExtractStateExtensionsFromEnhancerTuple<EnhancerTuple, {}>
151 : E extends ReadonlyArray<StoreEnhancer>
152 ? UnionToIntersection<
153 E[number] extends StoreEnhancer<any, infer StateExt>
154 ? StateExt extends {}
155 ? IsAny<StateExt, {}, StateExt>
156 : {}
157 : {}
158 >
159 : never
160
161/**
162 * Helper type. Passes T out again, but boxes it in a way that it cannot
163 * "widen" the type by accident if it is a generic that should be inferred
164 * from elsewhere.
165 *
166 * @internal
167 */
168export type NoInfer<T> = [T][T extends any ? 0 : never]
169
170export type NonUndefined<T> = T extends undefined ? never : T
171
172export type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>
173
174export type WithRequiredProp<T, K extends keyof T> = Omit<T, K> &
175 Required<Pick<T, K>>
176
177export type WithOptionalProp<T, K extends keyof T> = Omit<T, K> &
178 Partial<Pick<T, K>>
179
180export interface TypeGuard<T> {
181 (value: any): value is T
182}
183
184export interface HasMatchFunction<T> {
185 match: TypeGuard<T>
186}
187
188export const hasMatchFunction = <T>(
189 v: Matcher<T>,
190): v is HasMatchFunction<T> => {
191 return v && typeof (v as HasMatchFunction<T>).match === 'function'
192}
193
194/** @public */
195export type Matcher<T> = HasMatchFunction<T> | TypeGuard<T>
196
197/** @public */
198export type ActionFromMatcher<M extends Matcher<any>> =
199 M extends Matcher<infer T> ? T : never
200
201export type Id<T> = { [K in keyof T]: T[K] } & {}
202
203export type Tail<T extends any[]> = T extends [any, ...infer Tail]
204 ? Tail
205 : never
206
207export type UnknownIfNonSpecific<T> = {} extends T ? unknown : T
208
209/**
210 * A Promise that will never reject.
211 * @see https://github.com/reduxjs/redux-toolkit/issues/4101
212 */
213export type SafePromise<T> = Promise<T> & {
214 __linterBrands: 'SafePromise'
215}
216
217/**
218 * Properly wraps a Promise as a {@link SafePromise} with .catch(fallback).
219 */
220export function asSafePromise<Resolved, Rejected>(
221 promise: Promise<Resolved>,
222 fallback: (error: unknown) => Rejected,
223) {
224 return promise.catch(fallback) as SafePromise<Resolved | Rejected>
225}