UNPKG

9.84 kBPlain TextView Raw
1import type { ConditionalSimplifyDeep } from 'type-fest/source/conditional-simplify.js'
2
3/* eslint-disable */
4export type RemoveIndex<T> = {
5 [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K]
6}
7
8export const uppercase = <S extends string>(str: S): Uppercase<S> => str.toUpperCase() as Uppercase<S>
9
10export const callOrIdentity = <T>(value: MaybeLazy<T>) => {
11 return typeof value === `function` ? (value as () => T)() : value
12}
13
14export type MaybeLazy<T> = T | (() => T)
15
16export const zip = <A, B>(a: A[], b: B[]): [A, B | undefined][] => a.map((k, i) => [k, b[i]])
17
18export const HeadersInitToPlainObject = (headers?: HeadersInit): Record<string, string> => {
19 let oHeaders: Record<string, string> = {}
20
21 if (headers instanceof Headers) {
22 oHeaders = HeadersInstanceToPlainObject(headers)
23 } else if (Array.isArray(headers)) {
24 headers.forEach(([name, value]) => {
25 if (name && value !== undefined) {
26 oHeaders[name] = value
27 }
28 })
29 } else if (headers) {
30 oHeaders = headers
31 }
32
33 return oHeaders
34}
35
36export const HeadersInstanceToPlainObject = (headers: Response['headers']): Record<string, string> => {
37 const o: Record<string, string> = {}
38 headers.forEach((v, k) => {
39 o[k] = v
40 })
41 return o
42}
43
44export const tryCatch = <$Return, $Throw extends Error = Error>(
45 fn: () => $Return,
46): $Return extends Promise<any> ? Promise<Awaited<$Return> | $Throw> : $Return | $Throw => {
47 try {
48 const result = fn() as any
49 if (isPromiseLikeValue(result)) {
50 return result.catch((error) => {
51 return errorFromMaybeError(error)
52 }) as any
53 }
54 return result
55 } catch (error) {
56 return errorFromMaybeError(error) as any
57 }
58}
59
60/**
61 * Ensure that the given value is an error and return it. If it is not an error than
62 * wrap it in one, passing the given value as the error message.
63 */
64export const errorFromMaybeError = (maybeError: unknown): Error => {
65 if (maybeError instanceof Error) return maybeError
66 return new Error(String(maybeError))
67}
68
69export const isPromiseLikeValue = (value: unknown): value is Promise<unknown> => {
70 return (
71 typeof value === `object`
72 && value !== null
73 && `then` in value
74 && typeof value.then === `function`
75 && `catch` in value
76 && typeof value.catch === `function`
77 && `finally` in value
78 && typeof value.finally === `function`
79 )
80}
81
82export const casesExhausted = (value: never): never => {
83 throw new Error(`Unhandled case: ${String(value)}`)
84}
85
86export const isPlainObject = (value: unknown): value is Record<string, unknown> => {
87 return typeof value === `object` && value !== null && !Array.isArray(value)
88}
89
90export const entries = <T extends Record<string, any>>(obj: T) => Object.entries(obj) as [keyof T, T[keyof T]][]
91
92export const values = <T extends Record<string, unknown>>(obj: T): T[keyof T][] => Object.values(obj) as T[keyof T][]
93
94// dprint-ignore
95export type Exact<$Value, $Constraint> =
96 (
97 $Value extends unknown ? $Constraint extends $Value ? {} extends $Value ? $Constraint :
98 { [K in keyof $Value]: Exact<$Value[K], $Constraint[K]> } :
99 $Constraint :
100 never
101 )
102 | ($Value extends Narrowable ? $Value : never)
103
104// dprint-ignore
105// export type ExactObjectNonEmpty<$Value, $Constraint> =
106// (
107// $Value extends unknown ? $Constraint extends $Value ? keyof $Value extends never ? ({ 'TypeScript Error: You must supply at least one key.': true } & $Constraint) :
108// { [K in keyof $Value]: Exact<$Value[K], $Constraint[K]> } :
109// $Constraint :
110// never
111// )
112// | ($Value extends Narrowable ? $Value : never)
113
114export type Narrowable = string | number | bigint | boolean | []
115
116export type Letter = LetterLower | LetterUpper
117
118export type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
119
120export type LetterLower =
121 | 'a'
122 | 'b'
123 | 'c'
124 | 'd'
125 | 'e'
126 | 'f'
127 | 'g'
128 | 'h'
129 | 'i'
130 | 'j'
131 | 'k'
132 | 'l'
133 | 'm'
134 | 'n'
135 | 'o'
136 | 'p'
137 | 'q'
138 | 'r'
139 | 's'
140 | 't'
141 | 'u'
142 | 'v'
143 | 'w'
144 | 'x'
145 | 'y'
146 | 'z'
147export type LetterUpper =
148 | 'A'
149 | 'B'
150 | 'C'
151 | 'D'
152 | 'E'
153 | 'F'
154 | 'G'
155 | 'H'
156 | 'I'
157 | 'J'
158 | 'K'
159 | 'L'
160 | 'M'
161 | 'N'
162 | 'O'
163 | 'P'
164 | 'Q'
165 | 'R'
166 | 'S'
167 | 'T'
168 | 'U'
169 | 'V'
170 | 'W'
171 | 'X'
172 | 'Y'
173 | 'Z'
174
175export type StringNonEmpty = `${Letter}${string}`
176
177export type MaybeList<T> = T | T[]
178
179export type NotEmptyObject<T> = keyof T extends never ? never : T
180
181export type Values<T> = T[keyof T]
182
183export type GetKeyOr<T, Key, Or> = Key extends keyof T ? T[Key] : Or
184
185export type SimplifyDeep<T> = ConditionalSimplifyDeep<T, Function | Iterable<unknown> | Date, object>
186
187export type As<T, U> = U extends T ? U : never
188
189export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
190
191export type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R : never
192
193// TS4.0+
194export type Push<T extends any[], V> = [...T, V]
195
196// TS4.1+
197export type UnionToTuple<T, L = LastOf<T>, N = [T] extends [never] ? true : false> = true extends N ? []
198 : Push<UnionToTuple<Exclude<T, L>>, L>
199
200export type CountKeys<T> = keyof T extends never ? 0 : UnionToTuple<keyof T>['length']
201export type IsMultipleKeys<T> = IsMultiple<CountKeys<T>>
202export type IsMultiple<T> = T extends 0 ? false : T extends 1 ? false : true
203
204export type ExcludeNull<T> = Exclude<T, null>
205
206export const mapValues = <
207 $Obj extends Record<string, any>,
208 $Fn extends (value: $Obj[keyof $Obj], key: keyof $Obj) => any,
209>(
210 object: $Obj,
211 fn: $Fn,
212): Record<keyof $Obj, ReturnType<$Fn>> => {
213 return Object.fromEntries(
214 Object.entries(object).map(([key, value]) => {
215 return [key, fn(value, key)]
216 }),
217 ) as Record<keyof $Obj, ReturnType<$Fn>>
218}
219
220export type SetProperty<$Obj extends object, $Prop extends keyof $Obj, $Type extends $Obj[$Prop]> =
221 & Omit<$Obj, $Prop>
222 & { [_ in $Prop]: $Type }
223
224export const lowerCaseFirstLetter = (s: string) => {
225 return s.charAt(0).toLowerCase() + s.slice(1)
226}
227
228export function assertArray(v: unknown): asserts v is unknown[] {
229 if (!Array.isArray(v)) throw new Error(`Expected array. Got: ${String(v)}`)
230}
231
232export function assertObject(v: unknown): asserts v is object {
233 if (v === null || typeof v !== `object`) throw new Error(`Expected object. Got: ${String(v)}`)
234}
235
236export type StringKeyof<T> = keyof T & string
237
238export type MaybePromise<T> = T | Promise<T>
239
240export const capitalizeFirstLetter = (string: string) => string.charAt(0).toUpperCase() + string.slice(1)
241
242export type SomeAsyncFunction = (...args: unknown[]) => Promise<unknown>
243
244export type SomeMaybeAsyncFunction = (...args: unknown[]) => MaybePromise<unknown>
245
246export type Deferred<T> = {
247 promise: Promise<T>
248 isResolved: () => boolean
249 resolve: (value: T) => void
250 reject: (error: unknown) => void
251}
252
253export const createDeferred = <$T>(options?: { strict?: boolean }): Deferred<$T> => {
254 let isResolved = false
255 let resolve: (value: $T) => void
256 let reject: (error: unknown) => void
257
258 const promise = new Promise<$T>(($resolve, $reject) => {
259 resolve = $resolve
260 reject = $reject
261 })
262
263 return {
264 promise,
265 isResolved: () => isResolved,
266 resolve: (value) => {
267 isResolved = true
268 if (options?.strict && isResolved) {
269 throw new Error(`Deferred is already resolved. Attempted to resolve with: ${JSON.stringify(value)}`)
270 }
271 resolve(value)
272 },
273 reject: (error) => reject(error),
274 }
275}
276
277export const debug = (...args: any[]) => {
278 if (process.env[`DEBUG`]) {
279 console.log(...args)
280 }
281}
282
283export const debugSub = (...args: any[]) => (...subArgs: any[]) => {
284 debug(...args, ...subArgs)
285}
286
287export type PlusOneUpToTen<n extends number> = n extends 0 ? 1
288 : n extends 1 ? 2
289 : n extends 2 ? 3
290 : n extends 3 ? 4
291 : n extends 4 ? 5
292 : n extends 5 ? 6
293 : n extends 6 ? 7
294 : n extends 7 ? 8
295 : n extends 8 ? 9
296 : n extends 9 ? 10
297 : never
298
299export type MinusOneUpToTen<n extends number> = n extends 10 ? 9
300 : n extends 9 ? 8
301 : n extends 8 ? 7
302 : n extends 7 ? 6
303 : n extends 6 ? 5
304 : n extends 5 ? 4
305 : n extends 4 ? 3
306 : n extends 3 ? 2
307 : n extends 2 ? 1
308 : n extends 1 ? 0
309 : never
310
311export type findIndexForValue<value, list extends readonly [any, ...any[]]> = findIndexForValue_<value, list, 0>
312type findIndexForValue_<value, list extends readonly [any, ...any[]], i extends number> = value extends list[i] ? i
313 : findIndexForValue_<value, list, PlusOneUpToTen<i>>
314
315export type FindValueAfter<value, list extends readonly [any, ...any[]]> =
316 list[PlusOneUpToTen<findIndexForValue<value, list>>]
317
318export type ValueOr<value, orValue> = value extends undefined ? orValue : value
319
320export type FindValueAfterOr<value, list extends readonly [any, ...any[]], orValue> = ValueOr<
321 list[PlusOneUpToTen<findIndexForValue<value, list>>],
322 orValue
323>
324
325export type GetLastValue<T extends readonly [any, ...any[]]> = T[MinusOneUpToTen<T['length']>]
326
327export type IsLastValue<value, list extends readonly [any, ...any[]]> = value extends GetLastValue<list> ? true : false
328
329export type Include<T, U> = T extends U ? T : never
330
331export const partitionErrors = <T>(array: T[]): [Exclude<T, Error>[], Include<T, Error>[]] => {
332 const errors: Include<T, Error>[] = []
333 const values: Exclude<T, Error>[] = []
334 for (const item of array) {
335 if (item instanceof Error) {
336 errors.push(item as any)
337 } else {
338 values.push(item as any)
339 }
340 }
341 return [values, errors]
342}