| 1 | import type { Middleware, StoreEnhancer } from 'redux'
|
|---|
| 2 | import type { Tuple } from './utils'
|
|---|
| 3 |
|
|---|
| 4 | export 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 | */
|
|---|
| 17 | export 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 |
|
|---|
| 21 | export 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 | */
|
|---|
| 29 | export type IsUnknown<T, True, False = never> = unknown extends T
|
|---|
| 30 | ? IsAny<T, False, True>
|
|---|
| 31 | : False
|
|---|
| 32 |
|
|---|
| 33 | export type FallbackIfUnknown<T, Fallback> = IsUnknown<T, Fallback, T>
|
|---|
| 34 |
|
|---|
| 35 | /**
|
|---|
| 36 | * @internal
|
|---|
| 37 | */
|
|---|
| 38 | export type IfMaybeUndefined<P, True, False> = [undefined] extends [P]
|
|---|
| 39 | ? True
|
|---|
| 40 | : False
|
|---|
| 41 |
|
|---|
| 42 | /**
|
|---|
| 43 | * @internal
|
|---|
| 44 | */
|
|---|
| 45 | export type IfVoid<P, True, False> = [void] extends [P] ? True : False
|
|---|
| 46 |
|
|---|
| 47 | /**
|
|---|
| 48 | * @internal
|
|---|
| 49 | */
|
|---|
| 50 | export 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 | */
|
|---|
| 64 | export type AtLeastTS35<True, False> = [True, False][IsUnknown<
|
|---|
| 65 | ReturnType<<T>() => T>,
|
|---|
| 66 | 0,
|
|---|
| 67 | 1
|
|---|
| 68 | >]
|
|---|
| 69 |
|
|---|
| 70 | /**
|
|---|
| 71 | * @internal
|
|---|
| 72 | */
|
|---|
| 73 | export 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 | */
|
|---|
| 81 | export 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
|
|---|
| 88 | export 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 |
|
|---|
| 95 | type 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 |
|
|---|
| 105 | export type ExtractDispatchExtensions<M> =
|
|---|
| 106 | M extends Tuple<infer MiddlewareTuple>
|
|---|
| 107 | ? ExtractDispatchFromMiddlewareTuple<MiddlewareTuple, {}>
|
|---|
| 108 | : M extends ReadonlyArray<Middleware>
|
|---|
| 109 | ? ExtractDispatchFromMiddlewareTuple<[...M], {}>
|
|---|
| 110 | : never
|
|---|
| 111 |
|
|---|
| 112 | type 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 |
|
|---|
| 122 | export 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 |
|
|---|
| 135 | type 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 |
|
|---|
| 148 | export 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 | */
|
|---|
| 168 | export type NoInfer<T> = [T][T extends any ? 0 : never]
|
|---|
| 169 |
|
|---|
| 170 | export type NonUndefined<T> = T extends undefined ? never : T
|
|---|
| 171 |
|
|---|
| 172 | export type WithRequiredProp<T, K extends keyof T> = Omit<T, K> &
|
|---|
| 173 | Required<Pick<T, K>>
|
|---|
| 174 |
|
|---|
| 175 | export type WithOptionalProp<T, K extends keyof T> = Omit<T, K> &
|
|---|
| 176 | Partial<Pick<T, K>>
|
|---|
| 177 |
|
|---|
| 178 | export interface TypeGuard<T> {
|
|---|
| 179 | (value: any): value is T
|
|---|
| 180 | }
|
|---|
| 181 |
|
|---|
| 182 | export interface HasMatchFunction<T> {
|
|---|
| 183 | match: TypeGuard<T>
|
|---|
| 184 | }
|
|---|
| 185 |
|
|---|
| 186 | export const hasMatchFunction = <T>(
|
|---|
| 187 | v: Matcher<T>,
|
|---|
| 188 | ): v is HasMatchFunction<T> => {
|
|---|
| 189 | return v && typeof (v as HasMatchFunction<T>).match === 'function'
|
|---|
| 190 | }
|
|---|
| 191 |
|
|---|
| 192 | /** @public */
|
|---|
| 193 | export type Matcher<T> = HasMatchFunction<T> | TypeGuard<T>
|
|---|
| 194 |
|
|---|
| 195 | /** @public */
|
|---|
| 196 | export type ActionFromMatcher<M extends Matcher<any>> =
|
|---|
| 197 | M extends Matcher<infer T> ? T : never
|
|---|
| 198 |
|
|---|
| 199 | export type Id<T> = { [K in keyof T]: T[K] } & {}
|
|---|
| 200 |
|
|---|
| 201 | export type Tail<T extends any[]> = T extends [any, ...infer Tail]
|
|---|
| 202 | ? Tail
|
|---|
| 203 | : never
|
|---|
| 204 |
|
|---|
| 205 | export type UnknownIfNonSpecific<T> = {} extends T ? unknown : T
|
|---|
| 206 |
|
|---|
| 207 | /**
|
|---|
| 208 | * A Promise that will never reject.
|
|---|
| 209 | * @see https://github.com/reduxjs/redux-toolkit/issues/4101
|
|---|
| 210 | */
|
|---|
| 211 | export type SafePromise<T> = Promise<T> & {
|
|---|
| 212 | __linterBrands: 'SafePromise'
|
|---|
| 213 | }
|
|---|
| 214 |
|
|---|
| 215 | /**
|
|---|
| 216 | * Properly wraps a Promise as a {@link SafePromise} with .catch(fallback).
|
|---|
| 217 | */
|
|---|
| 218 | export function asSafePromise<Resolved, Rejected>(
|
|---|
| 219 | promise: Promise<Resolved>,
|
|---|
| 220 | fallback: (error: unknown) => Rejected,
|
|---|
| 221 | ) {
|
|---|
| 222 | return promise.catch(fallback) as SafePromise<Resolved | Rejected>
|
|---|
| 223 | }
|
|---|