@visulima/object 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2309 @@
1
+ /**
2
+ Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
3
+
4
+ @category Type
5
+ */
6
+ type Primitive =
7
+ | null
8
+ | undefined
9
+ | string
10
+ | number
11
+ | boolean
12
+ | symbol
13
+ | bigint;
14
+
15
+ declare global {
16
+ // eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- It has to be an `interface` so that it can be merged.
17
+ interface SymbolConstructor {
18
+ readonly observable: symbol;
19
+ }
20
+ }
21
+
22
+ declare const emptyObjectSymbol: unique symbol;
23
+
24
+ /**
25
+ Represents a strictly empty plain object, the `{}` value.
26
+
27
+ When you annotate something as the type `{}`, it can be anything except `null` and `undefined`. This means that you cannot use `{}` to represent an empty plain object ([read more](https://stackoverflow.com/questions/47339869/typescript-empty-object-and-any-difference/52193484#52193484)).
28
+
29
+ @example
30
+ ```
31
+ import type {EmptyObject} from 'type-fest';
32
+
33
+ // The following illustrates the problem with `{}`.
34
+ const foo1: {} = {}; // Pass
35
+ const foo2: {} = []; // Pass
36
+ const foo3: {} = 42; // Pass
37
+ const foo4: {} = {a: 1}; // Pass
38
+
39
+ // With `EmptyObject` only the first case is valid.
40
+ const bar1: EmptyObject = {}; // Pass
41
+ const bar2: EmptyObject = 42; // Fail
42
+ const bar3: EmptyObject = []; // Fail
43
+ const bar4: EmptyObject = {a: 1}; // Fail
44
+ ```
45
+
46
+ Unfortunately, `Record<string, never>`, `Record<keyof any, never>` and `Record<never, never>` do not work. See {@link https://github.com/sindresorhus/type-fest/issues/395 #395}.
47
+
48
+ @category Object
49
+ */
50
+ type EmptyObject = {[emptyObjectSymbol]?: never};
51
+
52
+ /**
53
+ Returns a boolean for whether the two given types are equal.
54
+
55
+ @link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
56
+ @link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796
57
+
58
+ Use-cases:
59
+ - If you want to make a conditional branch based on the result of a comparison of two types.
60
+
61
+ @example
62
+ ```
63
+ import type {IsEqual} from 'type-fest';
64
+
65
+ // This type returns a boolean for whether the given array includes the given item.
66
+ // `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal.
67
+ type Includes<Value extends readonly any[], Item> =
68
+ Value extends readonly [Value[0], ...infer rest]
69
+ ? IsEqual<Value[0], Item> extends true
70
+ ? true
71
+ : Includes<rest, Item>
72
+ : false;
73
+ ```
74
+
75
+ @category Type Guard
76
+ @category Utilities
77
+ */
78
+ type IsEqual<A, B> =
79
+ (<G>() => G extends A ? 1 : 2) extends
80
+ (<G>() => G extends B ? 1 : 2)
81
+ ? true
82
+ : false;
83
+
84
+ /**
85
+ Represents an array with `unknown` value.
86
+
87
+ Use case: You want a type that all arrays can be assigned to, but you don't care about the value.
88
+
89
+ @example
90
+ ```
91
+ import type {UnknownArray} from 'type-fest';
92
+
93
+ type IsArray<T> = T extends UnknownArray ? true : false;
94
+
95
+ type A = IsArray<['foo']>;
96
+ //=> true
97
+
98
+ type B = IsArray<readonly number[]>;
99
+ //=> true
100
+
101
+ type C = IsArray<string>;
102
+ //=> false
103
+ ```
104
+
105
+ @category Type
106
+ @category Array
107
+ */
108
+ type UnknownArray = readonly unknown[];
109
+
110
+ /**
111
+ Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
112
+
113
+ @example
114
+ ```
115
+ import type {Simplify} from 'type-fest';
116
+
117
+ type PositionProps = {
118
+ top: number;
119
+ left: number;
120
+ };
121
+
122
+ type SizeProps = {
123
+ width: number;
124
+ height: number;
125
+ };
126
+
127
+ // In your editor, hovering over `Props` will show a flattened object with all the properties.
128
+ type Props = Simplify<PositionProps & SizeProps>;
129
+ ```
130
+
131
+ Sometimes it is desired to pass a value as a function argument that has a different type. At first inspection it may seem assignable, and then you discover it is not because the `value`'s type definition was defined as an interface. In the following example, `fn` requires an argument of type `Record<string, unknown>`. If the value is defined as a literal, then it is assignable. And if the `value` is defined as type using the `Simplify` utility the value is assignable. But if the `value` is defined as an interface, it is not assignable because the interface is not sealed and elsewhere a non-string property could be added to the interface.
132
+
133
+ If the type definition must be an interface (perhaps it was defined in a third-party npm package), then the `value` can be defined as `const value: Simplify<SomeInterface> = ...`. Then `value` will be assignable to the `fn` argument. Or the `value` can be cast as `Simplify<SomeInterface>` if you can't re-declare the `value`.
134
+
135
+ @example
136
+ ```
137
+ import type {Simplify} from 'type-fest';
138
+
139
+ interface SomeInterface {
140
+ foo: number;
141
+ bar?: string;
142
+ baz: number | undefined;
143
+ }
144
+
145
+ type SomeType = {
146
+ foo: number;
147
+ bar?: string;
148
+ baz: number | undefined;
149
+ };
150
+
151
+ const literal = {foo: 123, bar: 'hello', baz: 456};
152
+ const someType: SomeType = literal;
153
+ const someInterface: SomeInterface = literal;
154
+
155
+ function fn(object: Record<string, unknown>): void {}
156
+
157
+ fn(literal); // Good: literal object type is sealed
158
+ fn(someType); // Good: type is sealed
159
+ fn(someInterface); // Error: Index signature for type 'string' is missing in type 'someInterface'. Because `interface` can be re-opened
160
+ fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface` into a `type`
161
+ ```
162
+
163
+ @link https://github.com/microsoft/TypeScript/issues/15300
164
+ @see SimplifyDeep
165
+ @category Object
166
+ */
167
+ type Simplify<T> = {[KeyType in keyof T]: T[KeyType]} & {};
168
+
169
+ /**
170
+ Returns a boolean for whether the given type is `any`.
171
+
172
+ @link https://stackoverflow.com/a/49928360/1490091
173
+
174
+ Useful in type utilities, such as disallowing `any`s to be passed to a function.
175
+
176
+ @example
177
+ ```
178
+ import type {IsAny} from 'type-fest';
179
+
180
+ const typedObject = {a: 1, b: 2} as const;
181
+ const anyObject: any = {a: 1, b: 2};
182
+
183
+ function get<O extends (IsAny<O> extends true ? {} : Record<string, number>), K extends keyof O = keyof O>(obj: O, key: K) {
184
+ return obj[key];
185
+ }
186
+
187
+ const typedA = get(typedObject, 'a');
188
+ //=> 1
189
+
190
+ const anyA = get(anyObject, 'a');
191
+ //=> any
192
+ ```
193
+
194
+ @category Type Guard
195
+ @category Utilities
196
+ */
197
+ type IsAny<T> = 0 extends 1 & T ? true : false;
198
+
199
+ type Numeric = number | bigint;
200
+
201
+ type Zero = 0 | 0n;
202
+
203
+ /**
204
+ Matches the hidden `Infinity` type.
205
+
206
+ Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/32277) if you want to have this type as a built-in in TypeScript.
207
+
208
+ @see NegativeInfinity
209
+
210
+ @category Numeric
211
+ */
212
+ // See https://github.com/microsoft/TypeScript/issues/31752
213
+ // eslint-disable-next-line @typescript-eslint/no-loss-of-precision
214
+ type PositiveInfinity = 1e999;
215
+
216
+ /**
217
+ Matches the hidden `-Infinity` type.
218
+
219
+ Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/32277) if you want to have this type as a built-in in TypeScript.
220
+
221
+ @see PositiveInfinity
222
+
223
+ @category Numeric
224
+ */
225
+ // See https://github.com/microsoft/TypeScript/issues/31752
226
+ // eslint-disable-next-line @typescript-eslint/no-loss-of-precision
227
+ type NegativeInfinity = -1e999;
228
+
229
+ /**
230
+ A negative `number`/`bigint` (`-∞ < x < 0`)
231
+
232
+ Use-case: Validating and documenting parameters.
233
+
234
+ @see NegativeInteger
235
+ @see NonNegative
236
+
237
+ @category Numeric
238
+ */
239
+ type Negative<T extends Numeric> = T extends Zero ? never : `${T}` extends `-${string}` ? T : never;
240
+
241
+ /**
242
+ Returns a boolean for whether the given number is a negative number.
243
+
244
+ @see Negative
245
+
246
+ @example
247
+ ```
248
+ import type {IsNegative} from 'type-fest';
249
+
250
+ type ShouldBeFalse = IsNegative<1>;
251
+ type ShouldBeTrue = IsNegative<-1>;
252
+ ```
253
+
254
+ @category Numeric
255
+ */
256
+ type IsNegative<T extends Numeric> = T extends Negative<T> ? true : false;
257
+
258
+ /**
259
+ Returns a boolean for whether two given types are both true.
260
+
261
+ Use-case: Constructing complex conditional types where multiple conditions must be satisfied.
262
+
263
+ @example
264
+ ```
265
+ import type {And} from 'type-fest';
266
+
267
+ And<true, true>;
268
+ //=> true
269
+
270
+ And<true, false>;
271
+ //=> false
272
+ ```
273
+
274
+ @see {@link Or}
275
+ */
276
+ type And<A extends boolean, B extends boolean> = [A, B][number] extends true
277
+ ? true
278
+ : true extends [IsEqual<A, false>, IsEqual<B, false>][number]
279
+ ? false
280
+ : never;
281
+
282
+ /**
283
+ Returns a boolean for whether either of two given types are true.
284
+
285
+ Use-case: Constructing complex conditional types where multiple conditions must be satisfied.
286
+
287
+ @example
288
+ ```
289
+ import type {Or} from 'type-fest';
290
+
291
+ Or<true, false>;
292
+ //=> true
293
+
294
+ Or<false, false>;
295
+ //=> false
296
+ ```
297
+
298
+ @see {@link And}
299
+ */
300
+ type Or<A extends boolean, B extends boolean> = [A, B][number] extends false
301
+ ? false
302
+ : true extends [IsEqual<A, true>, IsEqual<B, true>][number]
303
+ ? true
304
+ : never;
305
+
306
+ /**
307
+ Returns a boolean for whether a given number is greater than another number.
308
+
309
+ @example
310
+ ```
311
+ import type {GreaterThan} from 'type-fest';
312
+
313
+ GreaterThan<1, -5>;
314
+ //=> true
315
+
316
+ GreaterThan<1, 1>;
317
+ //=> false
318
+
319
+ GreaterThan<1, 5>;
320
+ //=> false
321
+ ```
322
+ */
323
+ type GreaterThan<A extends number, B extends number> = number extends A | B
324
+ ? never
325
+ : [
326
+ IsEqual<A, PositiveInfinity>, IsEqual<A, NegativeInfinity>,
327
+ IsEqual<B, PositiveInfinity>, IsEqual<B, NegativeInfinity>,
328
+ ] extends infer R extends [boolean, boolean, boolean, boolean]
329
+ ? Or<
330
+ And<IsEqual<R[0], true>, IsEqual<R[2], false>>,
331
+ And<IsEqual<R[3], true>, IsEqual<R[1], false>>
332
+ > extends true
333
+ ? true
334
+ : Or<
335
+ And<IsEqual<R[1], true>, IsEqual<R[3], false>>,
336
+ And<IsEqual<R[2], true>, IsEqual<R[0], false>>
337
+ > extends true
338
+ ? false
339
+ : true extends R[number]
340
+ ? false
341
+ : [IsNegative<A>, IsNegative<B>] extends infer R extends [boolean, boolean]
342
+ ? [true, false] extends R
343
+ ? false
344
+ : [false, true] extends R
345
+ ? true
346
+ : [false, false] extends R
347
+ ? PositiveNumericStringGt<`${A}`, `${B}`>
348
+ : PositiveNumericStringGt<`${NumberAbsolute<B>}`, `${NumberAbsolute<A>}`>
349
+ : never
350
+ : never;
351
+
352
+ /**
353
+ Returns a boolean for whether a given number is greater than or equal to another number.
354
+
355
+ @example
356
+ ```
357
+ import type {GreaterThanOrEqual} from 'type-fest';
358
+
359
+ GreaterThanOrEqual<1, -5>;
360
+ //=> true
361
+
362
+ GreaterThanOrEqual<1, 1>;
363
+ //=> true
364
+
365
+ GreaterThanOrEqual<1, 5>;
366
+ //=> false
367
+ ```
368
+ */
369
+ type GreaterThanOrEqual<A extends number, B extends number> = number extends A | B
370
+ ? never
371
+ : A extends B ? true : GreaterThan<A, B>;
372
+
373
+ /**
374
+ Returns a boolean for whether a given number is less than another number.
375
+
376
+ @example
377
+ ```
378
+ import type {LessThan} from 'type-fest';
379
+
380
+ LessThan<1, -5>;
381
+ //=> false
382
+
383
+ LessThan<1, 1>;
384
+ //=> false
385
+
386
+ LessThan<1, 5>;
387
+ //=> true
388
+ ```
389
+ */
390
+ type LessThan<A extends number, B extends number> = number extends A | B
391
+ ? never
392
+ : GreaterThanOrEqual<A, B> extends true ? false : true;
393
+
394
+ /**
395
+ Returns a boolean for whether the given type is `never`.
396
+
397
+ @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
398
+ @link https://stackoverflow.com/a/53984913/10292952
399
+ @link https://www.zhenghao.io/posts/ts-never
400
+
401
+ Useful in type utilities, such as checking if something does not occur.
402
+
403
+ @example
404
+ ```
405
+ import type {IsNever, And} from 'type-fest';
406
+
407
+ // https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts
408
+ type AreStringsEqual<A extends string, B extends string> =
409
+ And<
410
+ IsNever<Exclude<A, B>> extends true ? true : false,
411
+ IsNever<Exclude<B, A>> extends true ? true : false
412
+ >;
413
+
414
+ type EndIfEqual<I extends string, O extends string> =
415
+ AreStringsEqual<I, O> extends true
416
+ ? never
417
+ : void;
418
+
419
+ function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> {
420
+ if (input === output) {
421
+ process.exit(0);
422
+ }
423
+ }
424
+
425
+ endIfEqual('abc', 'abc');
426
+ //=> never
427
+
428
+ endIfEqual('abc', '123');
429
+ //=> void
430
+ ```
431
+
432
+ @category Type Guard
433
+ @category Utilities
434
+ */
435
+ type IsNever<T> = [T] extends [never] ? true : false;
436
+
437
+ /**
438
+ Infer the length of the given tuple `<T>`.
439
+
440
+ Returns `never` if the given type is an non-fixed-length array like `Array<string>`.
441
+
442
+ @example
443
+ ```
444
+ type Tuple = TupleLength<[string, number, boolean]>;
445
+ //=> 3
446
+
447
+ type Array = TupleLength<string[]>;
448
+ //=> never
449
+
450
+ // Supports union types.
451
+ type Union = TupleLength<[] | [1, 2, 3] | Array<number>>;
452
+ //=> 1 | 3
453
+ ```
454
+ */
455
+ type TupleLength<T extends UnknownArray> =
456
+ // `extends unknown` is used to convert `T` (if `T` is a union type) to
457
+ // a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types))
458
+ T extends unknown
459
+ ? number extends T['length']
460
+ ? never // Return never if the given type is an non-flexed-length array like `Array<string>`
461
+ : T['length']
462
+ : never; // Should never happen
463
+
464
+ /**
465
+ Create a tuple type of the given length `<L>` and fill it with the given type `<Fill>`.
466
+
467
+ If `<Fill>` is not provided, it will default to `unknown`.
468
+
469
+ @link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
470
+ */
471
+ type BuildTuple<L extends number, Fill = unknown, T extends readonly unknown[] = []> = T['length'] extends L
472
+ ? T
473
+ : BuildTuple<L, Fill, [...T, Fill]>;
474
+
475
+ /**
476
+ Create an object type with the given key `<Key>` and value `<Value>`.
477
+
478
+ It will copy the prefix and optional status of the same key from the given object `CopiedFrom` into the result.
479
+
480
+ @example
481
+ ```
482
+ type A = BuildObject<'a', string>;
483
+ //=> {a: string}
484
+
485
+ // Copy `readonly` and `?` from the key `a` of `{readonly a?: any}`
486
+ type B = BuildObject<'a', string, {readonly a?: any}>;
487
+ //=> {readonly a?: string}
488
+ ```
489
+ */
490
+ type BuildObject<Key extends PropertyKey, Value, CopiedFrom extends object = {}> =
491
+ Key extends keyof CopiedFrom
492
+ ? Pick<{[_ in keyof CopiedFrom]: Value}, Key>
493
+ : Key extends `${infer NumberKey extends number}`
494
+ ? NumberKey extends keyof CopiedFrom
495
+ ? Pick<{[_ in keyof CopiedFrom]: Value}, NumberKey>
496
+ : {[_ in Key]: Value}
497
+ : {[_ in Key]: Value};
498
+
499
+ /**
500
+ Return a string representation of the given string or number.
501
+
502
+ Note: This type is not the return type of the `.toString()` function.
503
+ */
504
+ type ToString<T> = T extends string | number ? `${T}` : never;
505
+
506
+ /**
507
+ Matches any primitive, `void`, `Date`, or `RegExp` value.
508
+ */
509
+ type BuiltIns = Primitive | void | Date | RegExp;
510
+
511
+ /**
512
+ Matches non-recursive types.
513
+ */
514
+ type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
515
+
516
+ /**
517
+ Converts a numeric string to a number.
518
+
519
+ @example
520
+ ```
521
+ type PositiveInt = StringToNumber<'1234'>;
522
+ //=> 1234
523
+
524
+ type NegativeInt = StringToNumber<'-1234'>;
525
+ //=> -1234
526
+
527
+ type PositiveFloat = StringToNumber<'1234.56'>;
528
+ //=> 1234.56
529
+
530
+ type NegativeFloat = StringToNumber<'-1234.56'>;
531
+ //=> -1234.56
532
+
533
+ type PositiveInfinity = StringToNumber<'Infinity'>;
534
+ //=> Infinity
535
+
536
+ type NegativeInfinity = StringToNumber<'-Infinity'>;
537
+ //=> -Infinity
538
+ ```
539
+
540
+ @category String
541
+ @category Numeric
542
+ @category Template literal
543
+ */
544
+ type StringToNumber<S extends string> = S extends `${infer N extends number}`
545
+ ? N
546
+ : S extends 'Infinity'
547
+ ? PositiveInfinity
548
+ : S extends '-Infinity'
549
+ ? NegativeInfinity
550
+ : never;
551
+
552
+ /**
553
+ Returns the length of the given string.
554
+
555
+ @example
556
+ ```
557
+ StringLength<'abcde'>;
558
+ //=> 5
559
+
560
+ StringLength<string>;
561
+ //=> never
562
+ ```
563
+
564
+ @category String
565
+ @category Template literal
566
+ */
567
+ type StringLength<S extends string> = string extends S
568
+ ? never
569
+ : StringToArray<S>['length'];
570
+
571
+ /**
572
+ Returns an array of the characters of the string.
573
+
574
+ @example
575
+ ```
576
+ StringToArray<'abcde'>;
577
+ //=> ['a', 'b', 'c', 'd', 'e']
578
+
579
+ StringToArray<string>;
580
+ //=> never
581
+ ```
582
+
583
+ @category String
584
+ */
585
+ type StringToArray<S extends string, Result extends string[] = []> = string extends S
586
+ ? never
587
+ : S extends `${infer F}${infer R}`
588
+ ? StringToArray<R, [...Result, F]>
589
+ : Result;
590
+
591
+ type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
592
+
593
+ /**
594
+ Extract the object field type if T is an object and K is a key of T, return `never` otherwise.
595
+
596
+ It creates a type-safe way to access the member type of `unknown` type.
597
+ */
598
+ type ObjectValue<T, K> =
599
+ K extends keyof T
600
+ ? T[K]
601
+ : ToString<K> extends keyof T
602
+ ? T[ToString<K>]
603
+ : K extends `${infer NumberK extends number}`
604
+ ? NumberK extends keyof T
605
+ ? T[NumberK]
606
+ : never
607
+ : never;
608
+
609
+ /**
610
+ Returns the maximum value from a tuple of integers.
611
+
612
+ Note:
613
+ - Float numbers are not supported.
614
+
615
+ @example
616
+ ```
617
+ ArrayMax<[1, 2, 5, 3]>;
618
+ //=> 5
619
+
620
+ ArrayMax<[1, 2, 5, 3, 99, -1]>;
621
+ //=> 99
622
+ ```
623
+ */
624
+ type ArrayMax<A extends number[], Result extends number = NegativeInfinity> = number extends A[number]
625
+ ? never :
626
+ A extends [infer F extends number, ...infer R extends number[]]
627
+ ? GreaterThan<F, Result> extends true
628
+ ? ArrayMax<R, F>
629
+ : ArrayMax<R, Result>
630
+ : Result;
631
+
632
+ /**
633
+ Returns the minimum value from a tuple of integers.
634
+
635
+ Note:
636
+ - Float numbers are not supported.
637
+
638
+ @example
639
+ ```
640
+ ArrayMin<[1, 2, 5, 3]>;
641
+ //=> 1
642
+
643
+ ArrayMin<[1, 2, 5, 3, -5]>;
644
+ //=> -5
645
+ ```
646
+ */
647
+ type ArrayMin<A extends number[], Result extends number = PositiveInfinity> = number extends A[number]
648
+ ? never
649
+ : A extends [infer F extends number, ...infer R extends number[]]
650
+ ? LessThan<F, Result> extends true
651
+ ? ArrayMin<R, F>
652
+ : ArrayMin<R, Result>
653
+ : Result;
654
+
655
+ /**
656
+ Returns the absolute value of a given value.
657
+
658
+ @example
659
+ ```
660
+ NumberAbsolute<-1>;
661
+ //=> 1
662
+
663
+ NumberAbsolute<1>;
664
+ //=> 1
665
+
666
+ NumberAbsolute<NegativeInfinity>
667
+ //=> PositiveInfinity
668
+ ```
669
+ */
670
+ type NumberAbsolute<N extends number> = `${N}` extends `-${infer StringPositiveN}` ? StringToNumber<StringPositiveN> : N;
671
+
672
+ /**
673
+ Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both numeric strings and have the same length.
674
+
675
+ @example
676
+ ```
677
+ SameLengthPositiveNumericStringGt<'50', '10'>;
678
+ //=> true
679
+
680
+ SameLengthPositiveNumericStringGt<'10', '10'>;
681
+ //=> false
682
+ ```
683
+ */
684
+ type SameLengthPositiveNumericStringGt<A extends string, B extends string> = A extends `${infer FirstA}${infer RestA}`
685
+ ? B extends `${infer FirstB}${infer RestB}`
686
+ ? FirstA extends FirstB
687
+ ? SameLengthPositiveNumericStringGt<RestA, RestB>
688
+ : PositiveNumericCharacterGt<FirstA, FirstB>
689
+ : never
690
+ : false;
691
+
692
+ type NumericString = '0123456789';
693
+
694
+ /**
695
+ Returns a boolean for whether `A` is greater than `B`, where `A` and `B` are both positive numeric strings.
696
+
697
+ @example
698
+ ```
699
+ PositiveNumericStringGt<'500', '1'>;
700
+ //=> true
701
+
702
+ PositiveNumericStringGt<'1', '1'>;
703
+ //=> false
704
+
705
+ PositiveNumericStringGt<'1', '500'>;
706
+ //=> false
707
+ ```
708
+ */
709
+ type PositiveNumericStringGt<A extends string, B extends string> = A extends B
710
+ ? false
711
+ : [BuildTuple<StringLength<A>, 0>, BuildTuple<StringLength<B>, 0>] extends infer R extends [readonly unknown[], readonly unknown[]]
712
+ ? R[0] extends [...R[1], ...infer Remain extends readonly unknown[]]
713
+ ? 0 extends Remain['length']
714
+ ? SameLengthPositiveNumericStringGt<A, B>
715
+ : true
716
+ : false
717
+ : never;
718
+
719
+ /**
720
+ Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both positive numeric characters.
721
+
722
+ @example
723
+ ```
724
+ PositiveNumericCharacterGt<'5', '1'>;
725
+ //=> true
726
+
727
+ PositiveNumericCharacterGt<'1', '1'>;
728
+ //=> false
729
+ ```
730
+ */
731
+ type PositiveNumericCharacterGt<A extends string, B extends string> = NumericString extends `${infer HeadA}${A}${infer TailA}`
732
+ ? NumericString extends `${infer HeadB}${B}${infer TailB}`
733
+ ? HeadA extends `${HeadB}${infer _}${infer __}`
734
+ ? true
735
+ : false
736
+ : never
737
+ : never;
738
+
739
+ /**
740
+ Returns the static, fixed-length portion of the given array, excluding variable-length parts.
741
+
742
+ @example
743
+ ```
744
+ type A = [string, number, boolean, ...string[]];
745
+ type B = StaticPartOfArray<A>;
746
+ //=> [string, number, boolean]
747
+ ```
748
+ */
749
+ type StaticPartOfArray<T extends UnknownArray, Result extends UnknownArray = []> =
750
+ T extends unknown
751
+ ? number extends T['length'] ?
752
+ T extends readonly [infer U, ...infer V]
753
+ ? StaticPartOfArray<V, [...Result, U]>
754
+ : Result
755
+ : T
756
+ : never; // Should never happen
757
+
758
+ /**
759
+ Returns the variable, non-fixed-length portion of the given array, excluding static-length parts.
760
+
761
+ @example
762
+ ```
763
+ type A = [string, number, boolean, ...string[]];
764
+ type B = VariablePartOfArray<A>;
765
+ //=> string[]
766
+ ```
767
+ */
768
+ type VariablePartOfArray<T extends UnknownArray> =
769
+ T extends unknown
770
+ ? T extends readonly [...StaticPartOfArray<T>, ...infer U]
771
+ ? U
772
+ : []
773
+ : never; // Should never happen
774
+
775
+ /**
776
+ Returns the minimum number in the given union of numbers.
777
+
778
+ Note: Just supports numbers from 0 to 999.
779
+
780
+ @example
781
+ ```
782
+ type A = UnionMin<3 | 1 | 2>;
783
+ //=> 1
784
+ ```
785
+ */
786
+ type UnionMin<N extends number> = InternalUnionMin<N>;
787
+
788
+ /**
789
+ The actual implementation of `UnionMin`. It's private because it has some arguments that don't need to be exposed.
790
+ */
791
+ type InternalUnionMin<N extends number, T extends UnknownArray = []> =
792
+ T['length'] extends N
793
+ ? T['length']
794
+ : InternalUnionMin<N, [...T, unknown]>;
795
+
796
+ /**
797
+ Returns the maximum number in the given union of numbers.
798
+
799
+ Note: Just supports numbers from 0 to 999.
800
+
801
+ @example
802
+ ```
803
+ type A = UnionMax<1 | 3 | 2>;
804
+ //=> 3
805
+ ```
806
+ */
807
+ type UnionMax<N extends number> = InternalUnionMax<N>;
808
+
809
+ /**
810
+ The actual implementation of `UnionMax`. It's private because it has some arguments that don't need to be exposed.
811
+ */
812
+ type InternalUnionMax<N extends number, T extends UnknownArray = []> =
813
+ IsNever<N> extends true
814
+ ? T['length']
815
+ : T['length'] extends N
816
+ ? InternalUnionMax<Exclude<N, T['length']>, T>
817
+ : InternalUnionMax<N, [...T, unknown]>;
818
+
819
+ /**
820
+ Returns a boolean for whether the given type is a union type.
821
+
822
+ @example
823
+ ```
824
+ type A = IsUnion<string | number>;
825
+ //=> true
826
+
827
+ type B = IsUnion<string>;
828
+ //=> false
829
+ ```
830
+ */
831
+ type IsUnion<T> = InternalIsUnion<T>;
832
+
833
+ /**
834
+ The actual implementation of `IsUnion`.
835
+ */
836
+ type InternalIsUnion<T, U = T> =
837
+ (
838
+ // @link https://ghaiklor.github.io/type-challenges-solutions/en/medium-isunion.html
839
+ IsNever<T> extends true
840
+ ? false
841
+ : T extends any
842
+ ? [U] extends [T]
843
+ ? false
844
+ : true
845
+ : never
846
+ ) extends infer Result
847
+ // In some cases `Result` will return `false | true` which is `boolean`,
848
+ // that means `T` has at least two types and it's a union type,
849
+ // so we will return `true` instead of `boolean`.
850
+ ? boolean extends Result ? true
851
+ : Result
852
+ : never; // Should never happen
853
+
854
+ /**
855
+ Set the given array to readonly if `IsReadonly` is `true`, otherwise set the given array to normal, then return the result.
856
+
857
+ @example
858
+ ```
859
+ type ReadonlyArray = readonly string[];
860
+ type NormalArray = string[];
861
+
862
+ type ReadonlyResult = SetArrayAccess<NormalArray, true>;
863
+ //=> readonly string[]
864
+
865
+ type NormalResult = SetArrayAccess<ReadonlyArray, false>;
866
+ //=> string[]
867
+ ```
868
+ */
869
+ type SetArrayAccess<T extends UnknownArray, IsReadonly extends boolean> =
870
+ T extends readonly [...infer U] ?
871
+ IsReadonly extends true
872
+ ? readonly [...U]
873
+ : [...U]
874
+ : T;
875
+
876
+ /**
877
+ Returns whether the given array `T` is readonly.
878
+ */
879
+ type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
880
+
881
+ /**
882
+ Get the exact version of the given `Key` in the given object `T`.
883
+
884
+ Use-case: You known that a number key (e.g. 10) is in an object, but you don't know how it is defined in the object, as a string or as a number (e.g. 10 or '10'). You can use this type to get the exact version of the key. See the example.
885
+
886
+ @example
887
+ ```
888
+ type Object = {
889
+ 0: number;
890
+ '1': string;
891
+ };
892
+
893
+ type Key1 = ExactKey<Object, '0'>;
894
+ //=> 0
895
+ type Key2 = ExactKey<Object, 0>;
896
+ //=> 0
897
+
898
+ type Key3 = ExactKey<Object, '1'>;
899
+ //=> '1'
900
+ type Key4 = ExactKey<Object, 1>;
901
+ //=> '1'
902
+ ```
903
+
904
+ @category Object
905
+ */
906
+ type ExactKey<T extends object, Key extends PropertyKey> =
907
+ Key extends keyof T
908
+ ? Key
909
+ : ToString<Key> extends keyof T
910
+ ? ToString<Key>
911
+ : Key extends `${infer NumberKey extends number}`
912
+ ? NumberKey extends keyof T
913
+ ? NumberKey
914
+ : never
915
+ : never;
916
+
917
+ /**
918
+ Deeply simplifies an object type.
919
+
920
+ You can exclude certain types from being simplified by providing them in the second generic `ExcludeType`.
921
+
922
+ Useful to flatten the type output to improve type hints shown in editors.
923
+
924
+ @example
925
+ ```
926
+ import type {SimplifyDeep} from 'type-fest';
927
+
928
+ type PositionX = {
929
+ left: number;
930
+ right: number;
931
+ };
932
+
933
+ type PositionY = {
934
+ top: number;
935
+ bottom: number;
936
+ };
937
+
938
+ type Properties1 = {
939
+ height: number;
940
+ position: PositionY;
941
+ };
942
+
943
+ type Properties2 = {
944
+ width: number;
945
+ position: PositionX;
946
+ };
947
+
948
+ type Properties = Properties1 & Properties2;
949
+ // In your editor, hovering over `Props` will show the following:
950
+ //
951
+ // type Properties = Properties1 & Properties2;
952
+
953
+ type SimplifyDeepProperties = SimplifyDeep<Properties1 & Properties2>;
954
+ // But if wrapped in SimplifyDeep, hovering over `SimplifyDeepProperties` will show a flattened object with all the properties:
955
+ //
956
+ // SimplifyDeepProperties = {
957
+ // height: number;
958
+ // width: number;
959
+ // position: {
960
+ // top: number;
961
+ // bottom: number;
962
+ // left: number;
963
+ // right: number;
964
+ // };
965
+ // };
966
+ ```
967
+
968
+ @example
969
+ ```
970
+ import type {SimplifyDeep} from 'type-fest';
971
+
972
+ // A complex type that you don't want or need to simplify
973
+ type ComplexType = {
974
+ a: string;
975
+ b: 'b';
976
+ c: number;
977
+ ...
978
+ };
979
+
980
+ type PositionX = {
981
+ left: number;
982
+ right: number;
983
+ };
984
+
985
+ type PositionY = {
986
+ top: number;
987
+ bottom: number;
988
+ };
989
+
990
+ // You want to simplify all other types
991
+ type Properties1 = {
992
+ height: number;
993
+ position: PositionY;
994
+ foo: ComplexType;
995
+ };
996
+
997
+ type Properties2 = {
998
+ width: number;
999
+ position: PositionX;
1000
+ foo: ComplexType;
1001
+ };
1002
+
1003
+ type SimplifyDeepProperties = SimplifyDeep<Properties1 & Properties2, ComplexType>;
1004
+ // If wrapped in `SimplifyDeep` and set `ComplexType` to exclude, hovering over `SimplifyDeepProperties` will
1005
+ // show a flattened object with all the properties except `ComplexType`:
1006
+ //
1007
+ // SimplifyDeepProperties = {
1008
+ // height: number;
1009
+ // width: number;
1010
+ // position: {
1011
+ // top: number;
1012
+ // bottom: number;
1013
+ // left: number;
1014
+ // right: number;
1015
+ // };
1016
+ // foo: ComplexType;
1017
+ // };
1018
+ ```
1019
+
1020
+ @see Simplify
1021
+ @category Object
1022
+ */
1023
+ type SimplifyDeep<Type, ExcludeType = never> =
1024
+ ConditionalSimplifyDeep<
1025
+ Type,
1026
+ ExcludeType | NonRecursiveType | Set<unknown> | Map<unknown, unknown>,
1027
+ object
1028
+ >;
1029
+
1030
+ /**
1031
+ Returns the difference between two numbers.
1032
+
1033
+ Note:
1034
+ - A or B can only support `-999` ~ `999`.
1035
+ - If the result is negative, you can only get `number`.
1036
+
1037
+ @example
1038
+ ```
1039
+ import type {Subtract} from 'type-fest';
1040
+
1041
+ Subtract<333, 222>;
1042
+ //=> 111
1043
+
1044
+ Subtract<111, -222>;
1045
+ //=> 333
1046
+
1047
+ Subtract<-111, 222>;
1048
+ //=> number
1049
+
1050
+ Subtract<PositiveInfinity, 9999>;
1051
+ //=> PositiveInfinity
1052
+
1053
+ Subtract<PositiveInfinity, PositiveInfinity>;
1054
+ //=> number
1055
+ ```
1056
+
1057
+ @category Numeric
1058
+ */
1059
+ // TODO: Support big integer and negative number.
1060
+ type Subtract<A extends number, B extends number> = number extends A | B
1061
+ ? number
1062
+ : [
1063
+ IsEqual<A, PositiveInfinity>, IsEqual<A, NegativeInfinity>,
1064
+ IsEqual<B, PositiveInfinity>, IsEqual<B, NegativeInfinity>,
1065
+ ] extends infer R extends [boolean, boolean, boolean, boolean]
1066
+ ? Or<
1067
+ And<IsEqual<R[0], true>, IsEqual<R[2], false>>,
1068
+ And<IsEqual<R[3], true>, IsEqual<R[1], false>>
1069
+ > extends true
1070
+ ? PositiveInfinity
1071
+ : Or<
1072
+ And<IsEqual<R[1], true>, IsEqual<R[3], false>>,
1073
+ And<IsEqual<R[2], true>, IsEqual<R[0], false>>
1074
+ > extends true
1075
+ ? NegativeInfinity
1076
+ : true extends R[number]
1077
+ ? number
1078
+ : [IsNegative<A>, IsNegative<B>] extends infer R
1079
+ ? [false, false] extends R
1080
+ ? BuildTuple<A> extends infer R
1081
+ ? R extends [...BuildTuple<B>, ...infer R]
1082
+ ? R['length']
1083
+ : number
1084
+ : never
1085
+ : LessThan<A, B> extends true
1086
+ ? number
1087
+ : [false, true] extends R
1088
+ ? Sum<A, NumberAbsolute<B>>
1089
+ : Subtract<NumberAbsolute<B>, NumberAbsolute<A>>
1090
+ : never
1091
+ : never;
1092
+
1093
+ /**
1094
+ Returns the sum of two numbers.
1095
+
1096
+ Note:
1097
+ - A or B can only support `-999` ~ `999`.
1098
+ - A and B can only be small integers, less than 1000.
1099
+ - If the result is negative, you can only get `number`.
1100
+
1101
+ @example
1102
+ ```
1103
+ import type {Sum} from 'type-fest';
1104
+
1105
+ Sum<111, 222>;
1106
+ //=> 333
1107
+
1108
+ Sum<-111, 222>;
1109
+ //=> 111
1110
+
1111
+ Sum<111, -222>;
1112
+ //=> number
1113
+
1114
+ Sum<PositiveInfinity, -9999>;
1115
+ //=> PositiveInfinity
1116
+
1117
+ Sum<PositiveInfinity, NegativeInfinity>;
1118
+ //=> number
1119
+ ```
1120
+
1121
+ @category Numeric
1122
+ */
1123
+ // TODO: Support big integer and negative number.
1124
+ type Sum<A extends number, B extends number> = number extends A | B
1125
+ ? number
1126
+ : [
1127
+ IsEqual<A, PositiveInfinity>, IsEqual<A, NegativeInfinity>,
1128
+ IsEqual<B, PositiveInfinity>, IsEqual<B, NegativeInfinity>,
1129
+ ] extends infer R extends [boolean, boolean, boolean, boolean]
1130
+ ? Or<
1131
+ And<IsEqual<R[0], true>, IsEqual<R[3], false>>,
1132
+ And<IsEqual<R[2], true>, IsEqual<R[1], false>>
1133
+ > extends true
1134
+ ? PositiveInfinity
1135
+ : Or<
1136
+ And<IsEqual<R[1], true>, IsEqual<R[2], false>>,
1137
+ And<IsEqual<R[3], true>, IsEqual<R[0], false>>
1138
+ > extends true
1139
+ ? NegativeInfinity
1140
+ : true extends R[number]
1141
+ ? number
1142
+ : ([IsNegative<A>, IsNegative<B>] extends infer R
1143
+ ? [false, false] extends R
1144
+ ? [...BuildTuple<A>, ...BuildTuple<B>]['length']
1145
+ : [true, true] extends R
1146
+ ? number
1147
+ : ArrayMax<[NumberAbsolute<A>, NumberAbsolute<B>]> extends infer Max_
1148
+ ? ArrayMin<[NumberAbsolute<A>, NumberAbsolute<B>]> extends infer Min_ extends number
1149
+ ? Max_ extends A | B
1150
+ ? Subtract<Max_, Min_>
1151
+ : number
1152
+ : never
1153
+ : never
1154
+ : never) & number
1155
+ : never;
1156
+
1157
+ /**
1158
+ Generate a union of all possible paths to properties in the given object.
1159
+
1160
+ It also works with arrays.
1161
+
1162
+ Use-case: You want a type-safe way to access deeply nested properties in an object.
1163
+
1164
+ @example
1165
+ ```
1166
+ import type {Paths} from 'type-fest';
1167
+
1168
+ type Project = {
1169
+ filename: string;
1170
+ listA: string[];
1171
+ listB: [{filename: string}];
1172
+ folder: {
1173
+ subfolder: {
1174
+ filename: string;
1175
+ };
1176
+ };
1177
+ };
1178
+
1179
+ type ProjectPaths = Paths<Project>;
1180
+ //=> 'filename' | 'listA' | 'listB' | 'folder' | `listA.${number}` | 'listB.0' | 'listB.0.filename' | 'folder.subfolder' | 'folder.subfolder.filename'
1181
+
1182
+ declare function open<Path extends ProjectPaths>(path: Path): void;
1183
+
1184
+ open('filename'); // Pass
1185
+ open('folder.subfolder'); // Pass
1186
+ open('folder.subfolder.filename'); // Pass
1187
+ open('foo'); // TypeError
1188
+
1189
+ // Also works with arrays
1190
+ open('listA.1'); // Pass
1191
+ open('listB.0'); // Pass
1192
+ open('listB.1'); // TypeError. Because listB only has one element.
1193
+ ```
1194
+
1195
+ @category Object
1196
+ @category Array
1197
+ */
1198
+ type Paths<T> = Paths_<T>;
1199
+
1200
+ type Paths_<T, Depth extends number = 0> =
1201
+ T extends NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
1202
+ ? never
1203
+ : IsAny<T> extends true
1204
+ ? never
1205
+ : T extends UnknownArray
1206
+ ? number extends T['length']
1207
+ // We need to handle the fixed and non-fixed index part of the array separately.
1208
+ ? InternalPaths<StaticPartOfArray<T>, Depth>
1209
+ | InternalPaths<Array<VariablePartOfArray<T>[number]>, Depth>
1210
+ : InternalPaths<T, Depth>
1211
+ : T extends object
1212
+ ? InternalPaths<T, Depth>
1213
+ : never;
1214
+
1215
+ type InternalPaths<_T, Depth extends number = 0, T = Required<_T>> =
1216
+ T extends EmptyObject | readonly []
1217
+ ? never
1218
+ : {
1219
+ [Key in keyof T]:
1220
+ Key extends string | number // Limit `Key` to string or number.
1221
+ // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
1222
+ ?
1223
+ | Key
1224
+ | ToString<Key>
1225
+ | (
1226
+ LessThan<Depth, 15> extends true // Limit the depth to prevent infinite recursion
1227
+ ? IsNever<Paths_<T[Key], Sum<Depth, 1>>> extends false
1228
+ ? `${Key}.${Paths_<T[Key], Sum<Depth, 1>>}`
1229
+ : never
1230
+ : never
1231
+ )
1232
+ : never
1233
+ }[keyof T & (T extends UnknownArray ? number : unknown)];
1234
+
1235
+ /**
1236
+ Convert a union type to an intersection type using [distributive conditional types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
1237
+
1238
+ Inspired by [this Stack Overflow answer](https://stackoverflow.com/a/50375286/2172153).
1239
+
1240
+ @example
1241
+ ```
1242
+ import type {UnionToIntersection} from 'type-fest';
1243
+
1244
+ type Union = {the(): void} | {great(arg: string): void} | {escape: boolean};
1245
+
1246
+ type Intersection = UnionToIntersection<Union>;
1247
+ //=> {the(): void; great(arg: string): void; escape: boolean};
1248
+ ```
1249
+
1250
+ A more applicable example which could make its way into your library code follows.
1251
+
1252
+ @example
1253
+ ```
1254
+ import type {UnionToIntersection} from 'type-fest';
1255
+
1256
+ class CommandOne {
1257
+ commands: {
1258
+ a1: () => undefined,
1259
+ b1: () => undefined,
1260
+ }
1261
+ }
1262
+
1263
+ class CommandTwo {
1264
+ commands: {
1265
+ a2: (argA: string) => undefined,
1266
+ b2: (argB: string) => undefined,
1267
+ }
1268
+ }
1269
+
1270
+ const union = [new CommandOne(), new CommandTwo()].map(instance => instance.commands);
1271
+ type Union = typeof union;
1272
+ //=> {a1(): void; b1(): void} | {a2(argA: string): void; b2(argB: string): void}
1273
+
1274
+ type Intersection = UnionToIntersection<Union>;
1275
+ //=> {a1(): void; b1(): void; a2(argA: string): void; b2(argB: string): void}
1276
+ ```
1277
+
1278
+ @category Type
1279
+ */
1280
+ type UnionToIntersection<Union> = (
1281
+ // `extends unknown` is always going to be the case and is used to convert the
1282
+ // `Union` into a [distributive conditional
1283
+ // type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
1284
+ Union extends unknown
1285
+ // The union type is used as the only argument to a function since the union
1286
+ // of function arguments is an intersection.
1287
+ ? (distributedUnion: Union) => void
1288
+ // This won't happen.
1289
+ : never
1290
+ // Infer the `Intersection` type since TypeScript represents the positional
1291
+ // arguments of unions of functions as an intersection of the union.
1292
+ ) extends ((mergedIntersection: infer Intersection) => void)
1293
+ // The `& Union` is to allow indexing by the resulting type
1294
+ ? Intersection & Union
1295
+ : never;
1296
+
1297
+ /**
1298
+ Pick properties from a deeply-nested object.
1299
+
1300
+ It supports recursing into arrays.
1301
+
1302
+ Use-case: Distill complex objects down to the components you need to target.
1303
+
1304
+ @example
1305
+ ```
1306
+ import type {PickDeep, PartialDeep} from 'type-fest';
1307
+
1308
+ type Configuration = {
1309
+ userConfig: {
1310
+ name: string;
1311
+ age: number;
1312
+ address: [
1313
+ {
1314
+ city1: string;
1315
+ street1: string;
1316
+ },
1317
+ {
1318
+ city2: string;
1319
+ street2: string;
1320
+ }
1321
+ ]
1322
+ };
1323
+ otherConfig: any;
1324
+ };
1325
+
1326
+ type NameConfig = PickDeep<Configuration, 'userConfig.name'>;
1327
+ // type NameConfig = {
1328
+ // userConfig: {
1329
+ // name: string;
1330
+ // }
1331
+ // };
1332
+
1333
+ // Supports optional properties
1334
+ type User = PickDeep<PartialDeep<Configuration>, 'userConfig.name' | 'userConfig.age'>;
1335
+ // type User = {
1336
+ // userConfig?: {
1337
+ // name?: string;
1338
+ // age?: number;
1339
+ // };
1340
+ // };
1341
+
1342
+ // Supports array
1343
+ type AddressConfig = PickDeep<Configuration, 'userConfig.address.0'>;
1344
+ // type AddressConfig = {
1345
+ // userConfig: {
1346
+ // address: [{
1347
+ // city1: string;
1348
+ // street1: string;
1349
+ // }];
1350
+ // };
1351
+ // }
1352
+
1353
+ // Supports recurse into array
1354
+ type Street = PickDeep<Configuration, 'userConfig.address.1.street2'>;
1355
+ // type Street = {
1356
+ // userConfig: {
1357
+ // address: [
1358
+ // unknown,
1359
+ // {street2: string}
1360
+ // ];
1361
+ // };
1362
+ // }
1363
+ ```
1364
+
1365
+ @category Object
1366
+ @category Array
1367
+ */
1368
+ type PickDeep<T, PathUnion extends Paths<T>> =
1369
+ T extends NonRecursiveType
1370
+ ? never
1371
+ : T extends UnknownArray
1372
+ ? UnionToIntersection<{
1373
+ [P in PathUnion]: InternalPickDeep<T, P>;
1374
+ }[PathUnion]
1375
+ >
1376
+ : T extends object
1377
+ ? Simplify<UnionToIntersection<{
1378
+ [P in PathUnion]: InternalPickDeep<T, P>;
1379
+ }[PathUnion]>>
1380
+ : never;
1381
+
1382
+ /**
1383
+ Pick an object/array from the given object/array by one path.
1384
+ */
1385
+ type InternalPickDeep<T, Path extends string | number> =
1386
+ T extends NonRecursiveType
1387
+ ? never
1388
+ : T extends UnknownArray ? PickDeepArray<T, Path>
1389
+ : T extends object ? Simplify<PickDeepObject<T, Path>>
1390
+ : never;
1391
+
1392
+ /**
1393
+ Pick an object from the given object by one path.
1394
+ */
1395
+ type PickDeepObject<RecordType extends object, P extends string | number> =
1396
+ P extends `${infer RecordKeyInPath}.${infer SubPath}`
1397
+ ? ObjectValue<RecordType, RecordKeyInPath> extends infer ObjectV
1398
+ ? IsNever<ObjectV> extends false
1399
+ ? BuildObject<RecordKeyInPath, InternalPickDeep<NonNullable<ObjectV>, SubPath>, RecordType>
1400
+ : never
1401
+ : never
1402
+ : ObjectValue<RecordType, P> extends infer ObjectV
1403
+ ? IsNever<ObjectV> extends false
1404
+ ? BuildObject<P, ObjectV, RecordType>
1405
+ : never
1406
+ : never;
1407
+
1408
+ /**
1409
+ Pick an array from the given array by one path.
1410
+ */
1411
+ type PickDeepArray<ArrayType extends UnknownArray, P extends string | number> =
1412
+ // Handle paths that are `${number}.${string}`
1413
+ P extends `${infer ArrayIndex extends number}.${infer SubPath}`
1414
+ // When `ArrayIndex` is equal to `number`
1415
+ ? number extends ArrayIndex
1416
+ ? ArrayType extends unknown[]
1417
+ ? Array<InternalPickDeep<NonNullable<ArrayType[number]>, SubPath>>
1418
+ : ArrayType extends readonly unknown[]
1419
+ ? ReadonlyArray<InternalPickDeep<NonNullable<ArrayType[number]>, SubPath>>
1420
+ : never
1421
+ // When `ArrayIndex` is a number literal
1422
+ : ArrayType extends unknown[]
1423
+ ? [...BuildTuple<ArrayIndex>, InternalPickDeep<NonNullable<ArrayType[ArrayIndex]>, SubPath>]
1424
+ : ArrayType extends readonly unknown[]
1425
+ ? readonly [...BuildTuple<ArrayIndex>, InternalPickDeep<NonNullable<ArrayType[ArrayIndex]>, SubPath>]
1426
+ : never
1427
+ // When the path is equal to `number`
1428
+ : P extends `${infer ArrayIndex extends number}`
1429
+ // When `ArrayIndex` is `number`
1430
+ ? number extends ArrayIndex
1431
+ ? ArrayType
1432
+ // When `ArrayIndex` is a number literal
1433
+ : ArrayType extends unknown[]
1434
+ ? [...BuildTuple<ArrayIndex>, ArrayType[ArrayIndex]]
1435
+ : ArrayType extends readonly unknown[]
1436
+ ? readonly [...BuildTuple<ArrayIndex>, ArrayType[ArrayIndex]]
1437
+ : never
1438
+ : never;
1439
+
1440
+ /**
1441
+ The implementation of `SplitArrayByIndex` for fixed length arrays.
1442
+ */
1443
+ type SplitFixedArrayByIndex<T extends UnknownArray, SplitIndex extends number> =
1444
+ SplitIndex extends 0
1445
+ ? [[], T]
1446
+ : T extends readonly [...BuildTuple<SplitIndex>, ...infer V]
1447
+ ? T extends readonly [...infer U, ...V]
1448
+ ? [U, V]
1449
+ : [never, never]
1450
+ : [never, never];
1451
+
1452
+ /**
1453
+ The implementation of `SplitArrayByIndex` for variable length arrays.
1454
+ */
1455
+ type SplitVariableArrayByIndex<T extends UnknownArray,
1456
+ SplitIndex extends number,
1457
+ T1 = Subtract<SplitIndex, StaticPartOfArray<T>['length']>,
1458
+ T2 = T1 extends number ? BuildTuple<T1, VariablePartOfArray<T>[number]> : [],
1459
+ > =
1460
+ SplitIndex extends 0
1461
+ ? [[], T]
1462
+ : GreaterThanOrEqual<StaticPartOfArray<T>['length'], SplitIndex> extends true
1463
+ ? [
1464
+ SplitFixedArrayByIndex<StaticPartOfArray<T>, SplitIndex>[0],
1465
+ [
1466
+ ...SplitFixedArrayByIndex<StaticPartOfArray<T>, SplitIndex>[1],
1467
+ ...VariablePartOfArray<T>,
1468
+ ],
1469
+ ]
1470
+ : [
1471
+ [
1472
+ ...StaticPartOfArray<T>,
1473
+ ...(T2 extends UnknownArray ? T2 : []),
1474
+ ],
1475
+ VariablePartOfArray<T>,
1476
+ ];
1477
+
1478
+ /**
1479
+ Split the given array `T` by the given `SplitIndex`.
1480
+
1481
+ @example
1482
+ ```
1483
+ type A = SplitArrayByIndex<[1, 2, 3, 4], 2>;
1484
+ // type A = [[1, 2], [3, 4]];
1485
+
1486
+ type B = SplitArrayByIndex<[1, 2, 3, 4], 0>;
1487
+ // type B = [[], [1, 2, 3, 4]];
1488
+ ```
1489
+ */
1490
+ type SplitArrayByIndex<T extends UnknownArray, SplitIndex extends number> =
1491
+ SplitIndex extends 0
1492
+ ? [[], T]
1493
+ : number extends T['length']
1494
+ ? SplitVariableArrayByIndex<T, SplitIndex>
1495
+ : SplitFixedArrayByIndex<T, SplitIndex>;
1496
+
1497
+ /**
1498
+ Creates a new array type by adding or removing elements at a specified index range in the original array.
1499
+
1500
+ Use-case: Replace or insert items in an array type.
1501
+
1502
+ Like [`Array#splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) but for types.
1503
+
1504
+ @example
1505
+ ```
1506
+ type SomeMonths0 = ['January', 'April', 'June'];
1507
+ type Mouths0 = ArraySplice<SomeMonths0, 1, 0, ['Feb', 'March']>;
1508
+ //=> type Mouths0 = ['January', 'Feb', 'March', 'April', 'June'];
1509
+
1510
+ type SomeMonths1 = ['January', 'April', 'June'];
1511
+ type Mouths1 = ArraySplice<SomeMonths1, 1, 1>;
1512
+ //=> type Mouths1 = ['January', 'June'];
1513
+
1514
+ type SomeMonths2 = ['January', 'Foo', 'April'];
1515
+ type Mouths2 = ArraySplice<SomeMonths2, 1, 1, ['Feb', 'March']>;
1516
+ //=> type Mouths2 = ['January', 'Feb', 'March', 'April'];
1517
+ ```
1518
+
1519
+ @category Array
1520
+ */
1521
+ type ArraySplice<
1522
+ T extends UnknownArray,
1523
+ Start extends number,
1524
+ DeleteCount extends number,
1525
+ Items extends UnknownArray = [],
1526
+ > =
1527
+ SplitArrayByIndex<T, Start> extends [infer U extends UnknownArray, infer V extends UnknownArray]
1528
+ ? SplitArrayByIndex<V, DeleteCount> extends [infer _Deleted extends UnknownArray, infer X extends UnknownArray]
1529
+ ? [...U, ...Items, ...X]
1530
+ : never // Should never happen
1531
+ : never; // Should never happen
1532
+
1533
+ /**
1534
+ Allows creating a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union.
1535
+
1536
+ Currently, when a union type of a primitive type is combined with literal types, TypeScript loses all information about the combined literals. Thus, when such type is used in an IDE with autocompletion, no suggestions are made for the declared literals.
1537
+
1538
+ This type is a workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729). It will be removed as soon as it's not needed anymore.
1539
+
1540
+ @example
1541
+ ```
1542
+ import type {LiteralUnion} from 'type-fest';
1543
+
1544
+ // Before
1545
+
1546
+ type Pet = 'dog' | 'cat' | string;
1547
+
1548
+ const pet: Pet = '';
1549
+ // Start typing in your TypeScript-enabled IDE.
1550
+ // You **will not** get auto-completion for `dog` and `cat` literals.
1551
+
1552
+ // After
1553
+
1554
+ type Pet2 = LiteralUnion<'dog' | 'cat', string>;
1555
+
1556
+ const pet: Pet2 = '';
1557
+ // You **will** get auto-completion for `dog` and `cat` literals.
1558
+ ```
1559
+
1560
+ @category Type
1561
+ */
1562
+ type LiteralUnion<
1563
+ LiteralType,
1564
+ BaseType extends Primitive,
1565
+ > = LiteralType | (BaseType & Record<never, never>);
1566
+
1567
+ /**
1568
+ SharedUnionFieldsDeep options.
1569
+
1570
+ @see {@link SharedUnionFieldsDeep}
1571
+ */
1572
+ type SharedUnionFieldsDeepOptions = {
1573
+ /**
1574
+ When set to true, this option impacts each element within arrays or tuples. If all union values are arrays or tuples, it constructs an array of the shortest possible length, ensuring every element exists in the union array.
1575
+
1576
+ @default false
1577
+ */
1578
+ recurseIntoArrays?: boolean;
1579
+ };
1580
+
1581
+ /**
1582
+ Create a type with shared fields from a union of object types, deeply traversing nested structures.
1583
+
1584
+ Use the {@link SharedUnionFieldsDeepOptions `Options`} to specify the behavior for arrays.
1585
+
1586
+ Use-cases:
1587
+ - You want a safe object type where each key exists in the union object.
1588
+ - You want to focus on the common fields of the union type and don't want to have to care about the other fields.
1589
+
1590
+ @example
1591
+ ```
1592
+ import type {SharedUnionFieldsDeep} from 'type-fest';
1593
+
1594
+ type Cat = {
1595
+ info: {
1596
+ name: string;
1597
+ type: 'cat';
1598
+ catType: string;
1599
+ };
1600
+ };
1601
+
1602
+ type Dog = {
1603
+ info: {
1604
+ name: string;
1605
+ type: 'dog';
1606
+ dogType: string;
1607
+ };
1608
+ };
1609
+
1610
+ function displayPetInfo(petInfo: (Cat | Dog)['info']) {
1611
+ // typeof petInfo =>
1612
+ // {
1613
+ // name: string;
1614
+ // type: 'cat';
1615
+ // catType: string; // Needn't care about this field, because it's not a common pet info field.
1616
+ // } | {
1617
+ // name: string;
1618
+ // type: 'dog';
1619
+ // dogType: string; // Needn't care about this field, because it's not a common pet info field.
1620
+ // }
1621
+
1622
+ // petInfo type is complex and have some needless fields
1623
+
1624
+ console.log('name: ', petInfo.name);
1625
+ console.log('type: ', petInfo.type);
1626
+ }
1627
+
1628
+ function displayPetInfo(petInfo: SharedUnionFieldsDeep<Cat | Dog>['info']) {
1629
+ // typeof petInfo =>
1630
+ // {
1631
+ // name: string;
1632
+ // type: 'cat' | 'dog';
1633
+ // }
1634
+
1635
+ // petInfo type is simple and clear
1636
+
1637
+ console.log('name: ', petInfo.name);
1638
+ console.log('type: ', petInfo.type);
1639
+ }
1640
+ ```
1641
+
1642
+ @category Object
1643
+ @category Union
1644
+ */
1645
+ type SharedUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions = {recurseIntoArrays: false}> =
1646
+ // If `Union` is not a union type, return `Union` directly.
1647
+ IsUnion<Union> extends false
1648
+ ? Union
1649
+ // `Union extends` will convert `Union`
1650
+ // to a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
1651
+ // But this is not what we want, so we need to wrap `Union` with `[]` to prevent it.
1652
+ : [Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
1653
+ ? Union
1654
+ : [Union] extends [UnknownArray]
1655
+ ? Options['recurseIntoArrays'] extends true
1656
+ ? SetArrayAccess<SharedArrayUnionFieldsDeep<Union, Options>, IsArrayReadonly<Union>>
1657
+ : Union
1658
+ : [Union] extends [object]
1659
+ ? SharedObjectUnionFieldsDeep<Union, Options>
1660
+ : Union;
1661
+
1662
+ /**
1663
+ Same as `SharedUnionFieldsDeep`, but accepts only `object`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
1664
+ */
1665
+ type SharedObjectUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions> =
1666
+ keyof Union extends infer Keys
1667
+ ? IsNever<Keys> extends false
1668
+ ? {
1669
+ [Key in keyof Union]:
1670
+ Union[Key] extends NonRecursiveType
1671
+ ? Union[Key]
1672
+ : SharedUnionFieldsDeep<Union[Key], Options>
1673
+ }
1674
+ : {}
1675
+ : Union;
1676
+
1677
+ /**
1678
+ Same as `SharedUnionFieldsDeep`, but accepts only `UnknownArray`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
1679
+ */
1680
+ type SharedArrayUnionFieldsDeep<Union extends UnknownArray, Options extends SharedUnionFieldsDeepOptions> =
1681
+ // Restore the readonly modifier of the array.
1682
+ SetArrayAccess<
1683
+ InternalSharedArrayUnionFieldsDeep<Union, Options>,
1684
+ IsArrayReadonly<Union>
1685
+ >;
1686
+
1687
+ /**
1688
+ Internal helper for `SharedArrayUnionFieldsDeep`. Needn't care the `readonly` modifier of arrays.
1689
+ */
1690
+ type InternalSharedArrayUnionFieldsDeep<
1691
+ Union extends UnknownArray,
1692
+ Options extends SharedUnionFieldsDeepOptions,
1693
+ ResultTuple extends UnknownArray = [],
1694
+ > =
1695
+ // We should build a minimum possible length tuple where each element in the tuple exists in the union tuple.
1696
+ IsNever<TupleLength<Union>> extends true
1697
+ // Rule 1: If all the arrays in the union have non-fixed lengths,
1698
+ // like `Array<string> | [number, ...string[]]`
1699
+ // we should build a tuple that is [the_fixed_parts_of_union, ...the_rest_of_union[]].
1700
+ // For example: `InternalSharedArrayUnionFieldsDeep<Array<string> | [number, ...string[]]>`
1701
+ // => `[string | number, ...string[]]`.
1702
+ ? ResultTuple['length'] extends UnionMax<StaticPartOfArray<Union>['length']>
1703
+ ? [
1704
+ // The fixed-length part of the tuple.
1705
+ ...ResultTuple,
1706
+ // The rest of the union.
1707
+ // Due to `ResultTuple` is the maximum possible fixed-length part of the tuple,
1708
+ // so we can use `StaticPartOfArray` to get the rest of the union.
1709
+ ...Array<
1710
+ SharedUnionFieldsDeep<VariablePartOfArray<Union>[number], Options>
1711
+ >,
1712
+ ]
1713
+ // Build the fixed-length tuple recursively.
1714
+ : InternalSharedArrayUnionFieldsDeep<
1715
+ Union, Options,
1716
+ [...ResultTuple, SharedUnionFieldsDeep<Union[ResultTuple['length']], Options>]
1717
+ >
1718
+ // Rule 2: If at least one of the arrays in the union have fixed lengths,
1719
+ // like `Array<string> | [number, string]`,
1720
+ // we should build a tuple of the smallest possible length to ensure any
1721
+ // item in the result tuple exists in the union tuple.
1722
+ // For example: `InternalSharedArrayUnionFieldsDeep<Array<string> | [number, string]>`
1723
+ // => `[string | number, string]`.
1724
+ : ResultTuple['length'] extends UnionMin<TupleLength<Union>>
1725
+ ? ResultTuple
1726
+ // As above, build tuple recursively.
1727
+ : InternalSharedArrayUnionFieldsDeep<
1728
+ Union, Options,
1729
+ [...ResultTuple, SharedUnionFieldsDeep<Union[ResultTuple['length']], Options>]
1730
+ >;
1731
+
1732
+ /**
1733
+ Omit properties from a deeply-nested object.
1734
+
1735
+ It supports recursing into arrays.
1736
+
1737
+ It supports removing specific items from an array, replacing each removed item with unknown at the specified index.
1738
+
1739
+ Use-case: Remove unneeded parts of complex objects.
1740
+
1741
+ Use [`Omit`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) if you only need one level deep.
1742
+
1743
+ @example
1744
+ ```
1745
+ import type {OmitDeep} from 'type-fest';
1746
+
1747
+ type Info = {
1748
+ userInfo: {
1749
+ name: string;
1750
+ uselessInfo: {
1751
+ foo: string;
1752
+ };
1753
+ };
1754
+ };
1755
+
1756
+ type UsefulInfo = OmitDeep<Info, 'userInfo.uselessInfo'>;
1757
+ // type UsefulInfo = {
1758
+ // userInfo: {
1759
+ // name: string;
1760
+ // };
1761
+
1762
+ // Supports array
1763
+ type A = OmitDeep<[1, 'foo', 2], 1>;
1764
+ // type A = [1, unknown, 2];
1765
+
1766
+ // Supports recursing into array
1767
+
1768
+ type Info1 = {
1769
+ address: [
1770
+ {
1771
+ street: string
1772
+ },
1773
+ {
1774
+ street2: string,
1775
+ foo: string
1776
+ };
1777
+ ];
1778
+ }
1779
+ type AddressInfo = OmitDeep<Info1, 'address.1.foo'>;
1780
+ // type AddressInfo = {
1781
+ // address: [
1782
+ // {
1783
+ // street: string;
1784
+ // },
1785
+ // {
1786
+ // street2: string;
1787
+ // };
1788
+ // ];
1789
+ // };
1790
+ ```
1791
+
1792
+ @category Object
1793
+ @category Array
1794
+ */
1795
+ type OmitDeep<T, PathUnion extends LiteralUnion<Paths<T>, string>> =
1796
+ SimplifyDeep<
1797
+ SharedUnionFieldsDeep<
1798
+ {[P in PathUnion]: OmitDeepWithOnePath<T, P>}[PathUnion]
1799
+ >,
1800
+ UnknownArray>;
1801
+
1802
+ /**
1803
+ Omit one path from the given object/array.
1804
+ */
1805
+ type OmitDeepWithOnePath<T, Path extends string | number> =
1806
+ T extends NonRecursiveType
1807
+ ? T
1808
+ : T extends UnknownArray ? SetArrayAccess<OmitDeepArrayWithOnePath<T, Path>, IsArrayReadonly<T>>
1809
+ : T extends object ? OmitDeepObjectWithOnePath<T, Path>
1810
+ : T;
1811
+
1812
+ /**
1813
+ Omit one path from the given object.
1814
+ */
1815
+ type OmitDeepObjectWithOnePath<ObjectT extends object, P extends string | number> =
1816
+ P extends `${infer RecordKeyInPath}.${infer SubPath}`
1817
+ ? {
1818
+ [Key in keyof ObjectT]:
1819
+ IsEqual<RecordKeyInPath, ToString<Key>> extends true
1820
+ ? ExactKey<ObjectT, Key> extends infer RealKey
1821
+ ? RealKey extends keyof ObjectT
1822
+ ? OmitDeepWithOnePath<ObjectT[RealKey], SubPath>
1823
+ : ObjectT[Key]
1824
+ : ObjectT[Key]
1825
+ : ObjectT[Key]
1826
+ }
1827
+ : ExactKey<ObjectT, P> extends infer Key
1828
+ ? IsNever<Key> extends true
1829
+ ? ObjectT
1830
+ : Key extends PropertyKey
1831
+ ? Omit<ObjectT, Key>
1832
+ : ObjectT
1833
+ : ObjectT;
1834
+
1835
+ /**
1836
+ Omit one path from from the given array.
1837
+
1838
+ It replaces the item to `unknown` at the given index.
1839
+
1840
+ @example
1841
+ ```
1842
+ type A = OmitDeepArrayWithOnePath<[10, 20, 30, 40], 2>;
1843
+ //=> type A = [10, 20, unknown, 40];
1844
+ ```
1845
+ */
1846
+ type OmitDeepArrayWithOnePath<ArrayType extends UnknownArray, P extends string | number> =
1847
+ // Handle paths that are `${number}.${string}`
1848
+ P extends `${infer ArrayIndex extends number}.${infer SubPath}`
1849
+ // If `ArrayIndex` is equal to `number`
1850
+ ? number extends ArrayIndex
1851
+ ? Array<OmitDeepWithOnePath<NonNullable<ArrayType[number]>, SubPath>>
1852
+ // If `ArrayIndex` is a number literal
1853
+ : ArraySplice<ArrayType, ArrayIndex, 1, [OmitDeepWithOnePath<NonNullable<ArrayType[ArrayIndex]>, SubPath>]>
1854
+ // If the path is equal to `number`
1855
+ : P extends `${infer ArrayIndex extends number}`
1856
+ // If `ArrayIndex` is `number`
1857
+ ? number extends ArrayIndex
1858
+ ? []
1859
+ // If `ArrayIndex` is a number literal
1860
+ : ArraySplice<ArrayType, ArrayIndex, 1, [unknown]>
1861
+ : ArrayType;
1862
+
1863
+ /**
1864
+ Get keys of the given type as strings.
1865
+
1866
+ Number keys are converted to strings.
1867
+
1868
+ Use-cases:
1869
+ - Get string keys from a type which may have number keys.
1870
+ - Makes it possible to index using strings retrieved from template types.
1871
+
1872
+ @example
1873
+ ```
1874
+ import type {StringKeyOf} from 'type-fest';
1875
+
1876
+ type Foo = {
1877
+ 1: number,
1878
+ stringKey: string,
1879
+ };
1880
+
1881
+ type StringKeysOfFoo = StringKeyOf<Foo>;
1882
+ //=> '1' | 'stringKey'
1883
+ ```
1884
+
1885
+ @category Object
1886
+ */
1887
+ type StringKeyOf<BaseType> = `${Extract<keyof BaseType, string | number>}`;
1888
+
1889
+ /**
1890
+ Represents an array of strings split using a given character or character set.
1891
+
1892
+ Use-case: Defining the return type of a method like `String.prototype.split`.
1893
+
1894
+ @example
1895
+ ```
1896
+ import type {Split} from 'type-fest';
1897
+
1898
+ declare function split<S extends string, D extends string>(string: S, separator: D): Split<S, D>;
1899
+
1900
+ type Item = 'foo' | 'bar' | 'baz' | 'waldo';
1901
+ const items = 'foo,bar,baz,waldo';
1902
+ let array: Item[];
1903
+
1904
+ array = split(items, ',');
1905
+ ```
1906
+
1907
+ @category String
1908
+ @category Template literal
1909
+ */
1910
+ type Split<
1911
+ S extends string,
1912
+ Delimiter extends string,
1913
+ > = S extends `${infer Head}${Delimiter}${infer Tail}`
1914
+ ? [Head, ...Split<Tail, Delimiter>]
1915
+ : S extends Delimiter
1916
+ ? []
1917
+ : [S];
1918
+
1919
+ type GetOptions = {
1920
+ /**
1921
+ Include `undefined` in the return type when accessing properties.
1922
+
1923
+ Setting this to `false` is not recommended.
1924
+
1925
+ @default true
1926
+ */
1927
+ strict?: boolean;
1928
+ };
1929
+
1930
+ /**
1931
+ Like the `Get` type but receives an array of strings as a path parameter.
1932
+ */
1933
+ type GetWithPath<BaseType, Keys extends readonly string[], Options extends GetOptions = {}> =
1934
+ Keys extends readonly []
1935
+ ? BaseType
1936
+ : Keys extends readonly [infer Head, ...infer Tail]
1937
+ ? GetWithPath<
1938
+ PropertyOf<BaseType, Extract<Head, string>, Options>,
1939
+ Extract<Tail, string[]>,
1940
+ Options
1941
+ >
1942
+ : never;
1943
+
1944
+ /**
1945
+ Adds `undefined` to `Type` if `strict` is enabled.
1946
+ */
1947
+ type Strictify<Type, Options extends GetOptions> =
1948
+ Options['strict'] extends false ? Type : (Type | undefined);
1949
+
1950
+ /**
1951
+ If `Options['strict']` is `true`, includes `undefined` in the returned type when accessing properties on `Record<string, any>`.
1952
+
1953
+ Known limitations:
1954
+ - Does not include `undefined` in the type on object types with an index signature (for example, `{a: string; [key: string]: string}`).
1955
+ */
1956
+ type StrictPropertyOf<BaseType, Key extends keyof BaseType, Options extends GetOptions> =
1957
+ Record<string, any> extends BaseType
1958
+ ? string extends keyof BaseType
1959
+ ? Strictify<BaseType[Key], Options> // Record<string, any>
1960
+ : BaseType[Key] // Record<'a' | 'b', any> (Records with a string union as keys have required properties)
1961
+ : BaseType[Key];
1962
+
1963
+ /**
1964
+ Splits a dot-prop style path into a tuple comprised of the properties in the path. Handles square-bracket notation.
1965
+
1966
+ @example
1967
+ ```
1968
+ ToPath<'foo.bar.baz'>
1969
+ //=> ['foo', 'bar', 'baz']
1970
+
1971
+ ToPath<'foo[0].bar.baz'>
1972
+ //=> ['foo', '0', 'bar', 'baz']
1973
+ ```
1974
+ */
1975
+ type ToPath<S extends string> = Split<FixPathSquareBrackets<S>, '.'>;
1976
+
1977
+ /**
1978
+ Replaces square-bracketed dot notation with dots, for example, `foo[0].bar` -> `foo.0.bar`.
1979
+ */
1980
+ type FixPathSquareBrackets<Path extends string> =
1981
+ Path extends `[${infer Head}]${infer Tail}`
1982
+ ? Tail extends `[${string}`
1983
+ ? `${Head}.${FixPathSquareBrackets<Tail>}`
1984
+ : `${Head}${FixPathSquareBrackets<Tail>}`
1985
+ : Path extends `${infer Head}[${infer Middle}]${infer Tail}`
1986
+ ? `${Head}.${FixPathSquareBrackets<`[${Middle}]${Tail}`>}`
1987
+ : Path;
1988
+
1989
+ /**
1990
+ Returns true if `LongString` is made up out of `Substring` repeated 0 or more times.
1991
+
1992
+ @example
1993
+ ```
1994
+ ConsistsOnlyOf<'aaa', 'a'> //=> true
1995
+ ConsistsOnlyOf<'ababab', 'ab'> //=> true
1996
+ ConsistsOnlyOf<'aBa', 'a'> //=> false
1997
+ ConsistsOnlyOf<'', 'a'> //=> true
1998
+ ```
1999
+ */
2000
+ type ConsistsOnlyOf<LongString extends string, Substring extends string> =
2001
+ LongString extends ''
2002
+ ? true
2003
+ : LongString extends `${Substring}${infer Tail}`
2004
+ ? ConsistsOnlyOf<Tail, Substring>
2005
+ : false;
2006
+
2007
+ /**
2008
+ Convert a type which may have number keys to one with string keys, making it possible to index using strings retrieved from template types.
2009
+
2010
+ @example
2011
+ ```
2012
+ type WithNumbers = {foo: string; 0: boolean};
2013
+ type WithStrings = WithStringKeys<WithNumbers>;
2014
+
2015
+ type WithNumbersKeys = keyof WithNumbers;
2016
+ //=> 'foo' | 0
2017
+ type WithStringsKeys = keyof WithStrings;
2018
+ //=> 'foo' | '0'
2019
+ ```
2020
+ */
2021
+ type WithStringKeys<BaseType> = {
2022
+ [Key in StringKeyOf<BaseType>]: UncheckedIndex<BaseType, Key>
2023
+ };
2024
+
2025
+ /**
2026
+ Perform a `T[U]` operation if `T` supports indexing.
2027
+ */
2028
+ type UncheckedIndex<T, U extends string | number> = [T] extends [Record<string | number, any>] ? T[U] : never;
2029
+
2030
+ /**
2031
+ Get a property of an object or array. Works when indexing arrays using number-literal-strings, for example, `PropertyOf<number[], '0'> = number`, and when indexing objects with number keys.
2032
+
2033
+ Note:
2034
+ - Returns `unknown` if `Key` is not a property of `BaseType`, since TypeScript uses structural typing, and it cannot be guaranteed that extra properties unknown to the type system will exist at runtime.
2035
+ - Returns `undefined` from nullish values, to match the behaviour of most deep-key libraries like `lodash`, `dot-prop`, etc.
2036
+ */
2037
+ type PropertyOf<BaseType, Key extends string, Options extends GetOptions = {}> =
2038
+ BaseType extends null | undefined
2039
+ ? undefined
2040
+ : Key extends keyof BaseType
2041
+ ? StrictPropertyOf<BaseType, Key, Options>
2042
+ : BaseType extends readonly [] | readonly [unknown, ...unknown[]]
2043
+ ? unknown // It's a tuple, but `Key` did not extend `keyof BaseType`. So the index is out of bounds.
2044
+ : BaseType extends {
2045
+ [n: number]: infer Item;
2046
+ length: number; // Note: This is needed to avoid being too lax with records types using number keys like `{0: string; 1: boolean}`.
2047
+ }
2048
+ ? (
2049
+ ConsistsOnlyOf<Key, StringDigit> extends true
2050
+ ? Strictify<Item, Options>
2051
+ : unknown
2052
+ )
2053
+ : Key extends keyof WithStringKeys<BaseType>
2054
+ ? StrictPropertyOf<WithStringKeys<BaseType>, Key, Options>
2055
+ : unknown;
2056
+
2057
+ // This works by first splitting the path based on `.` and `[...]` characters into a tuple of string keys. Then it recursively uses the head key to get the next property of the current object, until there are no keys left. Number keys extract the item type from arrays, or are converted to strings to extract types from tuples and dictionaries with number keys.
2058
+ /**
2059
+ Get a deeply-nested property from an object using a key path, like Lodash's `.get()` function.
2060
+
2061
+ Use-case: Retrieve a property from deep inside an API response or some other complex object.
2062
+
2063
+ @example
2064
+ ```
2065
+ import type {Get} from 'type-fest';
2066
+ import * as lodash from 'lodash';
2067
+
2068
+ const get = <BaseType, Path extends string | readonly string[]>(object: BaseType, path: Path): Get<BaseType, Path> =>
2069
+ lodash.get(object, path);
2070
+
2071
+ interface ApiResponse {
2072
+ hits: {
2073
+ hits: Array<{
2074
+ _id: string
2075
+ _source: {
2076
+ name: Array<{
2077
+ given: string[]
2078
+ family: string
2079
+ }>
2080
+ birthDate: string
2081
+ }
2082
+ }>
2083
+ }
2084
+ }
2085
+
2086
+ const getName = (apiResponse: ApiResponse) =>
2087
+ get(apiResponse, 'hits.hits[0]._source.name');
2088
+ //=> Array<{given: string[]; family: string}> | undefined
2089
+
2090
+ // Path also supports a readonly array of strings
2091
+ const getNameWithPathArray = (apiResponse: ApiResponse) =>
2092
+ get(apiResponse, ['hits','hits', '0', '_source', 'name'] as const);
2093
+ //=> Array<{given: string[]; family: string}> | undefined
2094
+
2095
+ // Non-strict mode:
2096
+ Get<string[], '3', {strict: false}> //=> string
2097
+ Get<Record<string, string>, 'foo', {strict: true}> // => string
2098
+ ```
2099
+
2100
+ @category Object
2101
+ @category Array
2102
+ @category Template literal
2103
+ */
2104
+ type Get<BaseType, Path extends string | readonly string[], Options extends GetOptions = {}> =
2105
+ GetWithPath<BaseType, Path extends string ? ToPath<Path> : Path, Options>;
2106
+
2107
+ declare const omit: <T extends { [key in string]: unknown; }, K extends string>(object: T, keys: Paths<T>[]) => OmitDeep<T, K>;
2108
+
2109
+ declare const pick: <T extends { [key in string]: unknown; }, K extends Paths<T>>(object: T, keys: Paths<T>[]) => PickDeep<T, K>;
2110
+
2111
+ interface DeeksOptions {
2112
+ /** @default false */
2113
+ arrayIndexesAsKeys?: boolean;
2114
+ /** @default true */
2115
+ expandNestedObjects?: boolean;
2116
+ /** @default false */
2117
+ expandArrayObjects?: boolean;
2118
+ /** @default false */
2119
+ ignoreEmptyArraysWhenExpanding?: boolean;
2120
+ /** @default false */
2121
+ escapeNestedDots?: boolean;
2122
+ /** @default false */
2123
+ ignoreEmptyArrays?: boolean;
2124
+ }
2125
+
2126
+ /**
2127
+ * Return the deep keys list for a single document
2128
+ * @param object
2129
+ * @param options
2130
+ * @returns {Array}
2131
+ */
2132
+ declare function deepKeys(object: object, options?: DeeksOptions): string[];
2133
+ /**
2134
+ * Return the deep keys list for all documents in the provided list
2135
+ * @param list
2136
+ * @param options
2137
+ * @returns Array[Array[String]]
2138
+ */
2139
+ declare function deepKeysFromList(list: object[], options?: DeeksOptions): string[][];
2140
+
2141
+ /**
2142
+ Get the value of the property at the given path.
2143
+
2144
+ @param object - Object or array to get the `path` value.
2145
+ @param path - Path of the property in the object, using `.` to separate each nested key. Use `\\.` if you have a `.` in the key.
2146
+ @param defaultValue - Default value.
2147
+
2148
+ @example
2149
+ ```
2150
+ import {getProperty} from 'dot-prop';
2151
+
2152
+ getProperty({foo: {bar: 'unicorn'}}, 'foo.bar');
2153
+ //=> 'unicorn'
2154
+
2155
+ getProperty({foo: {bar: 'a'}}, 'foo.notDefined.deep');
2156
+ //=> undefined
2157
+
2158
+ getProperty({foo: {bar: 'a'}}, 'foo.notDefined.deep', 'default value');
2159
+ //=> 'default value'
2160
+
2161
+ getProperty({foo: {'dot.dot': 'unicorn'}}, 'foo.dot\\.dot');
2162
+ //=> 'unicorn'
2163
+
2164
+ getProperty({foo: [{bar: 'unicorn'}]}, 'foo[0].bar');
2165
+ //=> 'unicorn'
2166
+ ```
2167
+ */
2168
+ declare function getProperty<ObjectType, PathType extends string, DefaultValue = undefined>(
2169
+ object: ObjectType,
2170
+ path: PathType,
2171
+ defaultValue?: DefaultValue
2172
+ ): ObjectType extends Record<string, unknown> | unknown[] ? (unknown extends Get<ObjectType, PathType> ? DefaultValue : Get<ObjectType, PathType>) : undefined;
2173
+
2174
+ /**
2175
+ Set the property at the given path to the given value.
2176
+
2177
+ @param object - Object or array to set the `path` value.
2178
+ @param path - Path of the property in the object, using `.` to separate each nested key. Use `\\.` if you have a `.` in the key.
2179
+ @param value - Value to set at `path`.
2180
+ @returns The object.
2181
+
2182
+ @example
2183
+ ```
2184
+ import {setProperty} from 'dot-prop';
2185
+
2186
+ const object = {foo: {bar: 'a'}};
2187
+ setProperty(object, 'foo.bar', 'b');
2188
+ console.log(object);
2189
+ //=> {foo: {bar: 'b'}}
2190
+
2191
+ const foo = setProperty({}, 'foo.bar', 'c');
2192
+ console.log(foo);
2193
+ //=> {foo: {bar: 'c'}}
2194
+
2195
+ setProperty(object, 'foo.baz', 'x');
2196
+ console.log(object);
2197
+ //=> {foo: {bar: 'b', baz: 'x'}}
2198
+
2199
+ setProperty(object, 'foo.biz[0]', 'a');
2200
+ console.log(object);
2201
+ //=> {foo: {bar: 'b', baz: 'x', biz: ['a']}}
2202
+ ```
2203
+ */
2204
+ declare function setProperty<ObjectType extends Record<string, any>>(
2205
+ object: ObjectType,
2206
+ path: string,
2207
+ value: unknown
2208
+ ): ObjectType;
2209
+
2210
+ /**
2211
+ Check whether the property at the given path exists.
2212
+
2213
+ @param object - Object or array to test the `path` value.
2214
+ @param path - Path of the property in the object, using `.` to separate each nested key. Use `\\.` if you have a `.` in the key.
2215
+
2216
+ @example
2217
+ ```
2218
+ import {hasProperty} from 'dot-prop';
2219
+
2220
+ hasProperty({foo: {bar: 'unicorn'}}, 'foo.bar');
2221
+ //=> true
2222
+ ```
2223
+ */
2224
+ declare function hasProperty(object: Record<string, any> | undefined, path: string): boolean;
2225
+
2226
+ /**
2227
+ Delete the property at the given path.
2228
+
2229
+ @param object - Object or array to delete the `path` value.
2230
+ @param path - Path of the property in the object, using `.` to separate each nested key. Use `\\.` if you have a `.` in the key.
2231
+ @returns A boolean of whether the property existed before being deleted.
2232
+
2233
+ @example
2234
+ ```
2235
+ import {deleteProperty} from 'dot-prop';
2236
+
2237
+ const object = {foo: {bar: 'a'}};
2238
+ deleteProperty(object, 'foo.bar');
2239
+ console.log(object);
2240
+ //=> {foo: {}}
2241
+
2242
+ object.foo.bar = {x: 'y', y: 'x'};
2243
+ deleteProperty(object, 'foo.bar.x');
2244
+ console.log(object);
2245
+ //=> {foo: {bar: {y: 'x'}}}
2246
+ ```
2247
+ */
2248
+ declare function deleteProperty(object: Record<string, any>, path: string): boolean;
2249
+
2250
+ /**
2251
+ Escape special characters in a path. Useful for sanitizing user input.
2252
+
2253
+ @param path - The dot path to sanitize.
2254
+
2255
+ @example
2256
+ ```
2257
+ import {getProperty, escapePath} from 'dot-prop';
2258
+
2259
+ const object = {
2260
+ foo: {
2261
+ bar: 'πŸ‘ΈπŸ» You found me Mario!',
2262
+ },
2263
+ 'foo.bar' : 'πŸ„ The princess is in another castle!',
2264
+ };
2265
+ const escapedPath = escapePath('foo.bar');
2266
+
2267
+ console.log(getProperty(object, escapedPath));
2268
+ //=> 'πŸ„ The princess is in another castle!'
2269
+ ```
2270
+ */
2271
+ declare function escapePath(path: string): string;
2272
+
2273
+ /**
2274
+ Check if a value is a plain object.
2275
+
2276
+ An object is plain if it's created by either `{}`, `new Object()`, or `Object.create(null)`.
2277
+
2278
+ @example
2279
+ ```
2280
+ import isPlainObject from 'is-plain-obj';
2281
+ import {runInNewContext} from 'node:vm';
2282
+
2283
+ isPlainObject({foo: 'bar'});
2284
+ //=> true
2285
+
2286
+ isPlainObject(new Object());
2287
+ //=> true
2288
+
2289
+ isPlainObject(Object.create(null));
2290
+ //=> true
2291
+
2292
+ // This works across realms
2293
+ isPlainObject(runInNewContext('({})'));
2294
+ //=> true
2295
+
2296
+ isPlainObject([1, 2, 3]);
2297
+ //=> false
2298
+
2299
+ class Unicorn {}
2300
+ isPlainObject(new Unicorn());
2301
+ //=> false
2302
+
2303
+ isPlainObject(Math);
2304
+ //=> false
2305
+ ```
2306
+ */
2307
+ declare function isPlainObject<Value>(value: unknown): value is Record<PropertyKey, Value>;
2308
+
2309
+ export { type DeeksOptions as DeepKeysOptions, type OmitDeep, type Paths, type PickDeep, type Split, deepKeys, deepKeysFromList, deleteProperty, escapePath, getProperty, hasProperty, isPlainObject, omit, pick, setProperty };