@visulima/object 1.0.8 → 1.0.10
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.
- package/CHANGELOG.md +23 -0
- package/README.md +2 -1
- package/dist/index.cjs +9 -9
- package/dist/index.d.cts +430 -430
- package/dist/index.d.mts +430 -430
- package/dist/index.d.ts +430 -430
- package/dist/index.mjs +9 -9
- package/dist/packem_shared/{getProperty-BuSUBWTY.cjs → getProperty-W4y1P_8H.cjs} +4 -4
- package/dist/packem_shared/{getProperty-CqSBQFGO.mjs → getProperty-uiEqCe4m.mjs} +4 -4
- package/package.json +3 -69
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,68 @@ declare global {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
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).
|
|
24
|
+
|
|
25
|
+
Inspired by [this Stack Overflow answer](https://stackoverflow.com/a/50375286/2172153).
|
|
26
|
+
|
|
27
|
+
@example
|
|
28
|
+
```
|
|
29
|
+
import type {UnionToIntersection} from 'type-fest';
|
|
30
|
+
|
|
31
|
+
type Union = {the(): void} | {great(arg: string): void} | {escape: boolean};
|
|
32
|
+
|
|
33
|
+
type Intersection = UnionToIntersection<Union>;
|
|
34
|
+
//=> {the(): void; great(arg: string): void; escape: boolean};
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
A more applicable example which could make its way into your library code follows.
|
|
38
|
+
|
|
39
|
+
@example
|
|
40
|
+
```
|
|
41
|
+
import type {UnionToIntersection} from 'type-fest';
|
|
42
|
+
|
|
43
|
+
class CommandOne {
|
|
44
|
+
commands: {
|
|
45
|
+
a1: () => undefined,
|
|
46
|
+
b1: () => undefined,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class CommandTwo {
|
|
51
|
+
commands: {
|
|
52
|
+
a2: (argA: string) => undefined,
|
|
53
|
+
b2: (argB: string) => undefined,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const union = [new CommandOne(), new CommandTwo()].map(instance => instance.commands);
|
|
58
|
+
type Union = typeof union;
|
|
59
|
+
//=> {a1(): void; b1(): void} | {a2(argA: string): void; b2(argB: string): void}
|
|
60
|
+
|
|
61
|
+
type Intersection = UnionToIntersection<Union>;
|
|
62
|
+
//=> {a1(): void; b1(): void; a2(argA: string): void; b2(argB: string): void}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
@category Type
|
|
66
|
+
*/
|
|
67
|
+
type UnionToIntersection<Union> = (
|
|
68
|
+
// `extends unknown` is always going to be the case and is used to convert the
|
|
69
|
+
// `Union` into a [distributive conditional
|
|
70
|
+
// type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
|
|
71
|
+
Union extends unknown
|
|
72
|
+
// The union type is used as the only argument to a function since the union
|
|
73
|
+
// of function arguments is an intersection.
|
|
74
|
+
? (distributedUnion: Union) => void
|
|
75
|
+
// This won't happen.
|
|
76
|
+
: never
|
|
77
|
+
// Infer the `Intersection` type since TypeScript represents the positional
|
|
78
|
+
// arguments of unions of functions as an intersection of the union.
|
|
79
|
+
) extends ((mergedIntersection: infer Intersection) => void)
|
|
80
|
+
// The `& Union` is to allow indexing by the resulting type
|
|
81
|
+
? Intersection & Union
|
|
82
|
+
: never;
|
|
83
|
+
|
|
22
84
|
declare const emptyObjectSymbol: unique symbol;
|
|
23
85
|
|
|
24
86
|
/**
|
|
@@ -390,6 +452,71 @@ type ShouldBeTrue = IsNegative<-1>;
|
|
|
390
452
|
*/
|
|
391
453
|
type IsNegative<T extends Numeric> = T extends Negative<T> ? true : false;
|
|
392
454
|
|
|
455
|
+
/**
|
|
456
|
+
Returns a boolean for whether the given type is a `string` [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types).
|
|
457
|
+
|
|
458
|
+
Useful for:
|
|
459
|
+
- providing strongly-typed string manipulation functions
|
|
460
|
+
- constraining strings to be a string literal
|
|
461
|
+
- type utilities, such as when constructing parsers and ASTs
|
|
462
|
+
|
|
463
|
+
The implementation of this type is inspired by the trick mentioned in this [StackOverflow answer](https://stackoverflow.com/a/68261113/420747).
|
|
464
|
+
|
|
465
|
+
@example
|
|
466
|
+
```
|
|
467
|
+
import type {IsStringLiteral} from 'type-fest';
|
|
468
|
+
|
|
469
|
+
type CapitalizedString<T extends string> = IsStringLiteral<T> extends true ? Capitalize<T> : string;
|
|
470
|
+
|
|
471
|
+
// https://github.com/yankeeinlondon/native-dash/blob/master/src/capitalize.ts
|
|
472
|
+
function capitalize<T extends Readonly<string>>(input: T): CapitalizedString<T> {
|
|
473
|
+
return (input.slice(0, 1).toUpperCase() + input.slice(1)) as CapitalizedString<T>;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const output = capitalize('hello, world!');
|
|
477
|
+
//=> 'Hello, world!'
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
@example
|
|
481
|
+
```
|
|
482
|
+
// String types with infinite set of possible values return `false`.
|
|
483
|
+
|
|
484
|
+
import type {IsStringLiteral} from 'type-fest';
|
|
485
|
+
|
|
486
|
+
type AllUppercaseStrings = IsStringLiteral<Uppercase<string>>;
|
|
487
|
+
//=> false
|
|
488
|
+
|
|
489
|
+
type StringsStartingWithOn = IsStringLiteral<`on${string}`>;
|
|
490
|
+
//=> false
|
|
491
|
+
|
|
492
|
+
// This behaviour is particularly useful in string manipulation utilities, as infinite string types often require separate handling.
|
|
493
|
+
|
|
494
|
+
type Length<S extends string, Counter extends never[] = []> =
|
|
495
|
+
IsStringLiteral<S> extends false
|
|
496
|
+
? number // return `number` for infinite string types
|
|
497
|
+
: S extends `${string}${infer Tail}`
|
|
498
|
+
? Length<Tail, [...Counter, never]>
|
|
499
|
+
: Counter['length'];
|
|
500
|
+
|
|
501
|
+
type L1 = Length<Lowercase<string>>;
|
|
502
|
+
//=> number
|
|
503
|
+
|
|
504
|
+
type L2 = Length<`${number}`>;
|
|
505
|
+
//=> number
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
@category Type Guard
|
|
509
|
+
@category Utilities
|
|
510
|
+
*/
|
|
511
|
+
type IsStringLiteral<T> = IfNever<T, false,
|
|
512
|
+
// If `T` is an infinite string type (e.g., `on${string}`), `Record<T, never>` produces an index signature,
|
|
513
|
+
// and since `{}` extends index signatures, the result becomes `false`.
|
|
514
|
+
T extends string
|
|
515
|
+
? {} extends Record<T, never>
|
|
516
|
+
? false
|
|
517
|
+
: true
|
|
518
|
+
: false>;
|
|
519
|
+
|
|
393
520
|
/**
|
|
394
521
|
Returns a boolean for whether two given types are both true.
|
|
395
522
|
|
|
@@ -526,32 +653,7 @@ type LessThan<A extends number, B extends number> = number extends A | B
|
|
|
526
653
|
? never
|
|
527
654
|
: GreaterThanOrEqual<A, B> extends true ? false : true;
|
|
528
655
|
|
|
529
|
-
|
|
530
|
-
Infer the length of the given tuple `<T>`.
|
|
531
|
-
|
|
532
|
-
Returns `never` if the given type is an non-fixed-length array like `Array<string>`.
|
|
533
|
-
|
|
534
|
-
@example
|
|
535
|
-
```
|
|
536
|
-
type Tuple = TupleLength<[string, number, boolean]>;
|
|
537
|
-
//=> 3
|
|
538
|
-
|
|
539
|
-
type Array = TupleLength<string[]>;
|
|
540
|
-
//=> never
|
|
541
|
-
|
|
542
|
-
// Supports union types.
|
|
543
|
-
type Union = TupleLength<[] | [1, 2, 3] | Array<number>>;
|
|
544
|
-
//=> 1 | 3
|
|
545
|
-
```
|
|
546
|
-
*/
|
|
547
|
-
type TupleLength<T extends UnknownArray> =
|
|
548
|
-
// `extends unknown` is used to convert `T` (if `T` is a union type) to
|
|
549
|
-
// a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types))
|
|
550
|
-
T extends unknown
|
|
551
|
-
? number extends T['length']
|
|
552
|
-
? never // Return never if the given type is an non-flexed-length array like `Array<string>`
|
|
553
|
-
: T['length']
|
|
554
|
-
: never; // Should never happen
|
|
656
|
+
// Should never happen
|
|
555
657
|
|
|
556
658
|
/**
|
|
557
659
|
Create a tuple type of the given length `<L>` and fill it with the given type `<Fill>`.
|
|
@@ -560,55 +662,11 @@ If `<Fill>` is not provided, it will default to `unknown`.
|
|
|
560
662
|
|
|
561
663
|
@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
|
|
562
664
|
*/
|
|
563
|
-
type BuildTuple<L extends number, Fill = unknown, T extends readonly unknown[] = []> =
|
|
564
|
-
?
|
|
565
|
-
:
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
Returns the maximum value from a tuple of integers.
|
|
569
|
-
|
|
570
|
-
Note:
|
|
571
|
-
- Float numbers are not supported.
|
|
572
|
-
|
|
573
|
-
@example
|
|
574
|
-
```
|
|
575
|
-
ArrayMax<[1, 2, 5, 3]>;
|
|
576
|
-
//=> 5
|
|
577
|
-
|
|
578
|
-
ArrayMax<[1, 2, 5, 3, 99, -1]>;
|
|
579
|
-
//=> 99
|
|
580
|
-
```
|
|
581
|
-
*/
|
|
582
|
-
type TupleMax<A extends number[], Result extends number = NegativeInfinity> = number extends A[number]
|
|
583
|
-
? never :
|
|
584
|
-
A extends [infer F extends number, ...infer R extends number[]]
|
|
585
|
-
? GreaterThan<F, Result> extends true
|
|
586
|
-
? TupleMax<R, F>
|
|
587
|
-
: TupleMax<R, Result>
|
|
588
|
-
: Result;
|
|
589
|
-
|
|
590
|
-
/**
|
|
591
|
-
Returns the minimum value from a tuple of integers.
|
|
592
|
-
|
|
593
|
-
Note:
|
|
594
|
-
- Float numbers are not supported.
|
|
595
|
-
|
|
596
|
-
@example
|
|
597
|
-
```
|
|
598
|
-
ArrayMin<[1, 2, 5, 3]>;
|
|
599
|
-
//=> 1
|
|
600
|
-
|
|
601
|
-
ArrayMin<[1, 2, 5, 3, -5]>;
|
|
602
|
-
//=> -5
|
|
603
|
-
```
|
|
604
|
-
*/
|
|
605
|
-
type TupleMin<A extends number[], Result extends number = PositiveInfinity> = number extends A[number]
|
|
606
|
-
? never
|
|
607
|
-
: A extends [infer F extends number, ...infer R extends number[]]
|
|
608
|
-
? LessThan<F, Result> extends true
|
|
609
|
-
? TupleMin<R, F>
|
|
610
|
-
: TupleMin<R, Result>
|
|
611
|
-
: Result;
|
|
665
|
+
type BuildTuple<L extends number, Fill = unknown, T extends readonly unknown[] = []> = number extends L
|
|
666
|
+
? Fill[]
|
|
667
|
+
: L extends T['length']
|
|
668
|
+
? T
|
|
669
|
+
: BuildTuple<L, Fill, [...T, Fill]>;
|
|
612
670
|
|
|
613
671
|
/**
|
|
614
672
|
Return a string representation of the given string or number.
|
|
@@ -840,48 +898,30 @@ type IsNumberLike<N> =
|
|
|
840
898
|
: false;
|
|
841
899
|
|
|
842
900
|
/**
|
|
843
|
-
Returns the
|
|
844
|
-
|
|
845
|
-
Note: Just supports numbers from 0 to 999.
|
|
901
|
+
Returns the number with reversed sign.
|
|
846
902
|
|
|
847
903
|
@example
|
|
848
904
|
```
|
|
849
|
-
|
|
905
|
+
ReverseSign<-1>;
|
|
850
906
|
//=> 1
|
|
851
|
-
```
|
|
852
|
-
*/
|
|
853
|
-
type UnionMin<N extends number> = InternalUnionMin<N>;
|
|
854
|
-
|
|
855
|
-
/**
|
|
856
|
-
The actual implementation of `UnionMin`. It's private because it has some arguments that don't need to be exposed.
|
|
857
|
-
*/
|
|
858
|
-
type InternalUnionMin<N extends number, T extends UnknownArray = []> =
|
|
859
|
-
T['length'] extends N
|
|
860
|
-
? T['length']
|
|
861
|
-
: InternalUnionMin<N, [...T, unknown]>;
|
|
862
907
|
|
|
863
|
-
|
|
864
|
-
|
|
908
|
+
ReverseSign<1>;
|
|
909
|
+
//=> -1
|
|
865
910
|
|
|
866
|
-
|
|
911
|
+
ReverseSign<NegativeInfinity>
|
|
912
|
+
//=> PositiveInfinity
|
|
867
913
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
type A = UnionMax<1 | 3 | 2>;
|
|
871
|
-
//=> 3
|
|
914
|
+
ReverseSign<PositiveInfinity>
|
|
915
|
+
//=> NegativeInfinity
|
|
872
916
|
```
|
|
873
917
|
*/
|
|
874
|
-
type
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
? T['length']
|
|
882
|
-
: T['length'] extends N
|
|
883
|
-
? InternalUnionMax<Exclude<N, T['length']>, T>
|
|
884
|
-
: InternalUnionMax<N, [...T, unknown]>;
|
|
918
|
+
type ReverseSign<N extends number> =
|
|
919
|
+
// Handle edge cases
|
|
920
|
+
N extends 0 ? 0 : N extends PositiveInfinity ? NegativeInfinity : N extends NegativeInfinity ? PositiveInfinity :
|
|
921
|
+
// Handle negative numbers
|
|
922
|
+
`${N}` extends `-${infer P extends number}` ? P
|
|
923
|
+
// Handle positive numbers
|
|
924
|
+
: `-${N}` extends `${infer R extends number}` ? R : never;
|
|
885
925
|
|
|
886
926
|
/**
|
|
887
927
|
Matches any primitive, `void`, `Date`, or `RegExp` value.
|
|
@@ -893,6 +933,24 @@ Matches non-recursive types.
|
|
|
893
933
|
*/
|
|
894
934
|
type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
|
|
895
935
|
|
|
936
|
+
/**
|
|
937
|
+
Returns a boolean for whether A is false.
|
|
938
|
+
|
|
939
|
+
@example
|
|
940
|
+
```
|
|
941
|
+
Not<true>;
|
|
942
|
+
//=> false
|
|
943
|
+
|
|
944
|
+
Not<false>;
|
|
945
|
+
//=> true
|
|
946
|
+
```
|
|
947
|
+
*/
|
|
948
|
+
type Not<A extends boolean> = A extends true
|
|
949
|
+
? false
|
|
950
|
+
: A extends false
|
|
951
|
+
? true
|
|
952
|
+
: never;
|
|
953
|
+
|
|
896
954
|
/**
|
|
897
955
|
Create an object type with the given key `<Key>` and value `<Value>`.
|
|
898
956
|
|
|
@@ -1046,76 +1104,11 @@ type SimplifyDeep<Type, ExcludeType = never> =
|
|
|
1046
1104
|
object
|
|
1047
1105
|
>;
|
|
1048
1106
|
|
|
1049
|
-
/**
|
|
1050
|
-
Returns the sum of two numbers.
|
|
1051
|
-
|
|
1052
|
-
Note:
|
|
1053
|
-
- A or B can only support `-999` ~ `999`.
|
|
1054
|
-
- A and B can only be small integers, less than 1000.
|
|
1055
|
-
- If the result is negative, you can only get `number`.
|
|
1056
|
-
|
|
1057
|
-
@example
|
|
1058
|
-
```
|
|
1059
|
-
import type {Sum} from 'type-fest';
|
|
1060
|
-
|
|
1061
|
-
Sum<111, 222>;
|
|
1062
|
-
//=> 333
|
|
1063
|
-
|
|
1064
|
-
Sum<-111, 222>;
|
|
1065
|
-
//=> 111
|
|
1066
|
-
|
|
1067
|
-
Sum<111, -222>;
|
|
1068
|
-
//=> number
|
|
1069
|
-
|
|
1070
|
-
Sum<PositiveInfinity, -9999>;
|
|
1071
|
-
//=> PositiveInfinity
|
|
1072
|
-
|
|
1073
|
-
Sum<PositiveInfinity, NegativeInfinity>;
|
|
1074
|
-
//=> number
|
|
1075
|
-
```
|
|
1076
|
-
|
|
1077
|
-
@category Numeric
|
|
1078
|
-
*/
|
|
1079
|
-
// TODO: Support big integer and negative number.
|
|
1080
|
-
type Sum<A extends number, B extends number> = number extends A | B
|
|
1081
|
-
? number
|
|
1082
|
-
: [
|
|
1083
|
-
IsEqual<A, PositiveInfinity>, IsEqual<A, NegativeInfinity>,
|
|
1084
|
-
IsEqual<B, PositiveInfinity>, IsEqual<B, NegativeInfinity>,
|
|
1085
|
-
] extends infer R extends [boolean, boolean, boolean, boolean]
|
|
1086
|
-
? Or<
|
|
1087
|
-
And<IsEqual<R[0], true>, IsEqual<R[3], false>>,
|
|
1088
|
-
And<IsEqual<R[2], true>, IsEqual<R[1], false>>
|
|
1089
|
-
> extends true
|
|
1090
|
-
? PositiveInfinity
|
|
1091
|
-
: Or<
|
|
1092
|
-
And<IsEqual<R[1], true>, IsEqual<R[2], false>>,
|
|
1093
|
-
And<IsEqual<R[3], true>, IsEqual<R[0], false>>
|
|
1094
|
-
> extends true
|
|
1095
|
-
? NegativeInfinity
|
|
1096
|
-
: true extends R[number]
|
|
1097
|
-
? number
|
|
1098
|
-
: ([IsNegative<A>, IsNegative<B>] extends infer R
|
|
1099
|
-
? [false, false] extends R
|
|
1100
|
-
? [...BuildTuple<A>, ...BuildTuple<B>]['length']
|
|
1101
|
-
: [true, true] extends R
|
|
1102
|
-
? number
|
|
1103
|
-
: TupleMax<[NumberAbsolute<A>, NumberAbsolute<B>]> extends infer Max_
|
|
1104
|
-
? TupleMin<[NumberAbsolute<A>, NumberAbsolute<B>]> extends infer Min_ extends number
|
|
1105
|
-
? Max_ extends A | B
|
|
1106
|
-
? Subtract<Max_, Min_>
|
|
1107
|
-
: number
|
|
1108
|
-
: never
|
|
1109
|
-
: never
|
|
1110
|
-
: never) & number
|
|
1111
|
-
: never;
|
|
1112
|
-
|
|
1113
1107
|
/**
|
|
1114
1108
|
Returns the difference between two numbers.
|
|
1115
1109
|
|
|
1116
1110
|
Note:
|
|
1117
1111
|
- A or B can only support `-999` ~ `999`.
|
|
1118
|
-
- If the result is negative, you can only get `number`.
|
|
1119
1112
|
|
|
1120
1113
|
@example
|
|
1121
1114
|
```
|
|
@@ -1128,7 +1121,10 @@ Subtract<111, -222>;
|
|
|
1128
1121
|
//=> 333
|
|
1129
1122
|
|
|
1130
1123
|
Subtract<-111, 222>;
|
|
1131
|
-
//=>
|
|
1124
|
+
//=> -333
|
|
1125
|
+
|
|
1126
|
+
Subtract<18, 96>;
|
|
1127
|
+
//=> -78
|
|
1132
1128
|
|
|
1133
1129
|
Subtract<PositiveInfinity, 9999>;
|
|
1134
1130
|
//=> PositiveInfinity
|
|
@@ -1139,38 +1135,53 @@ Subtract<PositiveInfinity, PositiveInfinity>;
|
|
|
1139
1135
|
|
|
1140
1136
|
@category Numeric
|
|
1141
1137
|
*/
|
|
1142
|
-
// TODO: Support big integer
|
|
1143
|
-
type Subtract<A extends number, B extends number> =
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1138
|
+
// TODO: Support big integer.
|
|
1139
|
+
type Subtract<A extends number, B extends number> =
|
|
1140
|
+
// Handle cases when A or B is the actual "number" type
|
|
1141
|
+
number extends A | B ? number
|
|
1142
|
+
// Handle cases when A and B are both +/- infinity
|
|
1143
|
+
: A extends B & (PositiveInfinity | NegativeInfinity) ? number
|
|
1144
|
+
// Handle cases when A is - infinity or B is + infinity
|
|
1145
|
+
: A extends NegativeInfinity ? NegativeInfinity : B extends PositiveInfinity ? NegativeInfinity
|
|
1146
|
+
// Handle cases when A is + infinity or B is - infinity
|
|
1147
|
+
: A extends PositiveInfinity ? PositiveInfinity : B extends NegativeInfinity ? PositiveInfinity
|
|
1148
|
+
// Handle case when numbers are equal to each other
|
|
1149
|
+
: A extends B ? 0
|
|
1150
|
+
// Handle cases when A or B is 0
|
|
1151
|
+
: A extends 0 ? ReverseSign<B> : B extends 0 ? A
|
|
1152
|
+
// Handle remaining regular cases
|
|
1153
|
+
: SubtractPostChecks<A, B>;
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
Subtracts two numbers A and B, such that they are not equal and neither of them are 0, +/- infinity or the `number` type
|
|
1157
|
+
*/
|
|
1158
|
+
type SubtractPostChecks<A extends number, B extends number, AreNegative = [IsNegative<A>, IsNegative<B>]> =
|
|
1159
|
+
AreNegative extends [false, false]
|
|
1160
|
+
? SubtractPositives<A, B>
|
|
1161
|
+
: AreNegative extends [true, true]
|
|
1162
|
+
// When both numbers are negative we subtract the absolute values and then reverse the sign
|
|
1163
|
+
? ReverseSign<SubtractPositives<NumberAbsolute<A>, NumberAbsolute<B>>>
|
|
1164
|
+
// When the signs are different we can add the absolute values and then reverse the sign if A < B
|
|
1165
|
+
: [...BuildTuple<NumberAbsolute<A>>, ...BuildTuple<NumberAbsolute<B>>] extends infer R extends unknown[]
|
|
1166
|
+
? LessThan<A, B> extends true ? ReverseSign<R['length']> : R['length']
|
|
1167
|
+
: never;
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
Subtracts two positive numbers.
|
|
1171
|
+
*/
|
|
1172
|
+
type SubtractPositives<A extends number, B extends number> =
|
|
1173
|
+
LessThan<A, B> extends true
|
|
1174
|
+
// When A < B we can reverse the result of B - A
|
|
1175
|
+
? ReverseSign<SubtractIfAGreaterThanB<B, A>>
|
|
1176
|
+
: SubtractIfAGreaterThanB<A, B>;
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
Subtracts two positive numbers A and B such that A > B.
|
|
1180
|
+
*/
|
|
1181
|
+
type SubtractIfAGreaterThanB<A extends number, B extends number> =
|
|
1182
|
+
// This is where we always want to end up and do the actual subtraction
|
|
1183
|
+
BuildTuple<A> extends [...BuildTuple<B>, ...infer R]
|
|
1184
|
+
? R['length']
|
|
1174
1185
|
: never;
|
|
1175
1186
|
|
|
1176
1187
|
/**
|
|
@@ -1218,11 +1229,89 @@ type PathsOptions = {
|
|
|
1218
1229
|
```
|
|
1219
1230
|
*/
|
|
1220
1231
|
bracketNotation?: boolean;
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
Only include leaf paths in the output.
|
|
1235
|
+
|
|
1236
|
+
@default false
|
|
1237
|
+
|
|
1238
|
+
@example
|
|
1239
|
+
```
|
|
1240
|
+
type Post = {
|
|
1241
|
+
id: number;
|
|
1242
|
+
author: {
|
|
1243
|
+
id: number;
|
|
1244
|
+
name: {
|
|
1245
|
+
first: string;
|
|
1246
|
+
last: string;
|
|
1247
|
+
};
|
|
1248
|
+
};
|
|
1249
|
+
};
|
|
1250
|
+
|
|
1251
|
+
type AllPaths = Paths<Post, {leavesOnly: false}>;
|
|
1252
|
+
//=> 'id' | 'author' | 'author.id' | 'author.name' | 'author.name.first' | 'author.name.last'
|
|
1253
|
+
|
|
1254
|
+
type LeafPaths = Paths<Post, {leavesOnly: true}>;
|
|
1255
|
+
//=> 'id' | 'author.id' | 'author.name.first' | 'author.name.last'
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
@example
|
|
1259
|
+
```
|
|
1260
|
+
type ArrayExample = {
|
|
1261
|
+
array: Array<{foo: string}>;
|
|
1262
|
+
tuple: [string, {bar: string}];
|
|
1263
|
+
};
|
|
1264
|
+
|
|
1265
|
+
type AllPaths = Paths<ArrayExample, {leavesOnly: false}>;
|
|
1266
|
+
//=> 'array' | `array.${number}` | `array.${number}.foo` | 'tuple' | 'tuple.0' | 'tuple.1' | 'tuple.1.bar'
|
|
1267
|
+
|
|
1268
|
+
type LeafPaths = Paths<ArrayExample, {leavesOnly: true}>;
|
|
1269
|
+
//=> `array.${number}.foo` | 'tuple.0' | 'tuple.1.bar'
|
|
1270
|
+
```
|
|
1271
|
+
*/
|
|
1272
|
+
leavesOnly?: boolean;
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
Only include paths at the specified depth. By default all paths up to {@link PathsOptions.maxRecursionDepth | `maxRecursionDepth`} are included.
|
|
1276
|
+
|
|
1277
|
+
Note: Depth starts at `0` for root properties.
|
|
1278
|
+
|
|
1279
|
+
@default number
|
|
1280
|
+
|
|
1281
|
+
@example
|
|
1282
|
+
```
|
|
1283
|
+
type Post = {
|
|
1284
|
+
id: number;
|
|
1285
|
+
author: {
|
|
1286
|
+
id: number;
|
|
1287
|
+
name: {
|
|
1288
|
+
first: string;
|
|
1289
|
+
last: string;
|
|
1290
|
+
};
|
|
1291
|
+
};
|
|
1292
|
+
};
|
|
1293
|
+
|
|
1294
|
+
type DepthZero = Paths<Post, {depth: 0}>;
|
|
1295
|
+
//=> 'id' | 'author'
|
|
1296
|
+
|
|
1297
|
+
type DepthOne = Paths<Post, {depth: 1}>;
|
|
1298
|
+
//=> 'author.id' | 'author.name'
|
|
1299
|
+
|
|
1300
|
+
type DepthTwo = Paths<Post, {depth: 2}>;
|
|
1301
|
+
//=> 'author.name.first' | 'author.name.last'
|
|
1302
|
+
|
|
1303
|
+
type LeavesAtDepthOne = Paths<Post, {leavesOnly: true; depth: 1}>;
|
|
1304
|
+
//=> 'author.id'
|
|
1305
|
+
```
|
|
1306
|
+
*/
|
|
1307
|
+
depth?: number;
|
|
1221
1308
|
};
|
|
1222
1309
|
|
|
1223
1310
|
type DefaultPathsOptions = {
|
|
1224
1311
|
maxRecursionDepth: 10;
|
|
1225
1312
|
bracketNotation: false;
|
|
1313
|
+
leavesOnly: false;
|
|
1314
|
+
depth: number;
|
|
1226
1315
|
};
|
|
1227
1316
|
|
|
1228
1317
|
/**
|
|
@@ -1271,6 +1360,10 @@ type Paths<T, Options extends PathsOptions = {}> = _Paths<T, {
|
|
|
1271
1360
|
maxRecursionDepth: Options['maxRecursionDepth'] extends number ? Options['maxRecursionDepth'] : DefaultPathsOptions['maxRecursionDepth'];
|
|
1272
1361
|
// Set default bracketNotation to false
|
|
1273
1362
|
bracketNotation: Options['bracketNotation'] extends boolean ? Options['bracketNotation'] : DefaultPathsOptions['bracketNotation'];
|
|
1363
|
+
// Set default leavesOnly to false
|
|
1364
|
+
leavesOnly: Options['leavesOnly'] extends boolean ? Options['leavesOnly'] : DefaultPathsOptions['leavesOnly'];
|
|
1365
|
+
// Set default depth to number
|
|
1366
|
+
depth: Options['depth'] extends number ? Options['depth'] : DefaultPathsOptions['depth'];
|
|
1274
1367
|
}>;
|
|
1275
1368
|
|
|
1276
1369
|
type _Paths<T, Options extends Required<PathsOptions>> =
|
|
@@ -1310,11 +1403,30 @@ type InternalPaths<T, Options extends Required<PathsOptions>> =
|
|
|
1310
1403
|
) extends infer TranformedKey extends string | number ?
|
|
1311
1404
|
// 1. If style is 'a[0].b' and 'Key' is a numberlike value like 3 or '3', transform 'Key' to `[${Key}]`, else to `${Key}` | Key
|
|
1312
1405
|
// 2. If style is 'a.0.b', transform 'Key' to `${Key}` | Key
|
|
1313
|
-
|
|
|
1406
|
+
| ((Options['leavesOnly'] extends true
|
|
1407
|
+
? MaxDepth extends 0
|
|
1408
|
+
? TranformedKey
|
|
1409
|
+
: T[Key] extends EmptyObject | readonly [] | NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
|
|
1410
|
+
? TranformedKey
|
|
1411
|
+
: never
|
|
1412
|
+
: TranformedKey
|
|
1413
|
+
) extends infer _TransformedKey
|
|
1414
|
+
// If `depth` is provided, the condition becomes truthy only when it reaches `0`.
|
|
1415
|
+
// Otherwise, since `depth` defaults to `number`, the condition is always truthy, returning paths at all depths.
|
|
1416
|
+
? 0 extends Options['depth']
|
|
1417
|
+
? _TransformedKey
|
|
1418
|
+
: never
|
|
1419
|
+
: never)
|
|
1314
1420
|
| (
|
|
1315
1421
|
// Recursively generate paths for the current key
|
|
1316
1422
|
GreaterThan<MaxDepth, 0> extends true // Limit the depth to prevent infinite recursion
|
|
1317
|
-
? _Paths<T[Key],
|
|
1423
|
+
? _Paths<T[Key],
|
|
1424
|
+
{
|
|
1425
|
+
bracketNotation: Options['bracketNotation'];
|
|
1426
|
+
maxRecursionDepth: Subtract<MaxDepth, 1>;
|
|
1427
|
+
leavesOnly: Options['leavesOnly'];
|
|
1428
|
+
depth: Subtract<Options['depth'], 1>;
|
|
1429
|
+
}> extends infer SubPath
|
|
1318
1430
|
? SubPath extends string | number
|
|
1319
1431
|
? (
|
|
1320
1432
|
Options['bracketNotation'] extends true
|
|
@@ -1337,68 +1449,6 @@ type InternalPaths<T, Options extends Required<PathsOptions>> =
|
|
|
1337
1449
|
: never
|
|
1338
1450
|
: never;
|
|
1339
1451
|
|
|
1340
|
-
/**
|
|
1341
|
-
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).
|
|
1342
|
-
|
|
1343
|
-
Inspired by [this Stack Overflow answer](https://stackoverflow.com/a/50375286/2172153).
|
|
1344
|
-
|
|
1345
|
-
@example
|
|
1346
|
-
```
|
|
1347
|
-
import type {UnionToIntersection} from 'type-fest';
|
|
1348
|
-
|
|
1349
|
-
type Union = {the(): void} | {great(arg: string): void} | {escape: boolean};
|
|
1350
|
-
|
|
1351
|
-
type Intersection = UnionToIntersection<Union>;
|
|
1352
|
-
//=> {the(): void; great(arg: string): void; escape: boolean};
|
|
1353
|
-
```
|
|
1354
|
-
|
|
1355
|
-
A more applicable example which could make its way into your library code follows.
|
|
1356
|
-
|
|
1357
|
-
@example
|
|
1358
|
-
```
|
|
1359
|
-
import type {UnionToIntersection} from 'type-fest';
|
|
1360
|
-
|
|
1361
|
-
class CommandOne {
|
|
1362
|
-
commands: {
|
|
1363
|
-
a1: () => undefined,
|
|
1364
|
-
b1: () => undefined,
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
class CommandTwo {
|
|
1369
|
-
commands: {
|
|
1370
|
-
a2: (argA: string) => undefined,
|
|
1371
|
-
b2: (argB: string) => undefined,
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
const union = [new CommandOne(), new CommandTwo()].map(instance => instance.commands);
|
|
1376
|
-
type Union = typeof union;
|
|
1377
|
-
//=> {a1(): void; b1(): void} | {a2(argA: string): void; b2(argB: string): void}
|
|
1378
|
-
|
|
1379
|
-
type Intersection = UnionToIntersection<Union>;
|
|
1380
|
-
//=> {a1(): void; b1(): void; a2(argA: string): void; b2(argB: string): void}
|
|
1381
|
-
```
|
|
1382
|
-
|
|
1383
|
-
@category Type
|
|
1384
|
-
*/
|
|
1385
|
-
type UnionToIntersection<Union> = (
|
|
1386
|
-
// `extends unknown` is always going to be the case and is used to convert the
|
|
1387
|
-
// `Union` into a [distributive conditional
|
|
1388
|
-
// type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
|
|
1389
|
-
Union extends unknown
|
|
1390
|
-
// The union type is used as the only argument to a function since the union
|
|
1391
|
-
// of function arguments is an intersection.
|
|
1392
|
-
? (distributedUnion: Union) => void
|
|
1393
|
-
// This won't happen.
|
|
1394
|
-
: never
|
|
1395
|
-
// Infer the `Intersection` type since TypeScript represents the positional
|
|
1396
|
-
// arguments of unions of functions as an intersection of the union.
|
|
1397
|
-
) extends ((mergedIntersection: infer Intersection) => void)
|
|
1398
|
-
// The `& Union` is to allow indexing by the resulting type
|
|
1399
|
-
? Intersection & Union
|
|
1400
|
-
: never;
|
|
1401
|
-
|
|
1402
1452
|
/**
|
|
1403
1453
|
Pick properties from a deeply-nested object.
|
|
1404
1454
|
|
|
@@ -1560,7 +1610,9 @@ The implementation of `SplitArrayByIndex` for variable length arrays.
|
|
|
1560
1610
|
type SplitVariableArrayByIndex<T extends UnknownArray,
|
|
1561
1611
|
SplitIndex extends number,
|
|
1562
1612
|
T1 = Subtract<SplitIndex, StaticPartOfArray<T>['length']>,
|
|
1563
|
-
T2 = T1 extends number
|
|
1613
|
+
T2 = T1 extends number
|
|
1614
|
+
? BuildTuple<GreaterThanOrEqual<T1, 0> extends true ? T1 : number, VariablePartOfArray<T>[number]>
|
|
1615
|
+
: [],
|
|
1564
1616
|
> =
|
|
1565
1617
|
SplitIndex extends 0
|
|
1566
1618
|
? [[], T]
|
|
@@ -1672,173 +1724,58 @@ type LiteralUnion<
|
|
|
1672
1724
|
> = LiteralType | (BaseType & Record<never, never>);
|
|
1673
1725
|
|
|
1674
1726
|
/**
|
|
1675
|
-
|
|
1727
|
+
Returns the last element of a union type.
|
|
1676
1728
|
|
|
1677
|
-
@
|
|
1729
|
+
@example
|
|
1730
|
+
```
|
|
1731
|
+
type Last = LastOfUnion<1 | 2 | 3>;
|
|
1732
|
+
//=> 3
|
|
1733
|
+
```
|
|
1678
1734
|
*/
|
|
1679
|
-
type
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
@default false
|
|
1684
|
-
*/
|
|
1685
|
-
recurseIntoArrays?: boolean;
|
|
1686
|
-
};
|
|
1735
|
+
type LastOfUnion<T> =
|
|
1736
|
+
UnionToIntersection<T extends any ? () => T : never> extends () => (infer R)
|
|
1737
|
+
? R
|
|
1738
|
+
: never;
|
|
1687
1739
|
|
|
1688
1740
|
/**
|
|
1689
|
-
|
|
1741
|
+
Convert a union type into an unordered tuple type of its elements.
|
|
1690
1742
|
|
|
1691
|
-
|
|
1743
|
+
"Unordered" means the elements of the tuple are not guaranteed to be in the same order as in the union type. The arrangement can appear random and may change at any time.
|
|
1692
1744
|
|
|
1693
|
-
|
|
1694
|
-
- You want a safe object type where each key exists in the union object.
|
|
1695
|
-
- You want to focus on the common fields of the union type and don't want to have to care about the other fields.
|
|
1745
|
+
This can be useful when you have objects with a finite set of keys and want a type defining only the allowed keys, but do not want to repeat yourself.
|
|
1696
1746
|
|
|
1697
1747
|
@example
|
|
1698
1748
|
```
|
|
1699
|
-
import type {
|
|
1749
|
+
import type {UnionToTuple} from 'type-fest';
|
|
1700
1750
|
|
|
1701
|
-
type
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
catType: string;
|
|
1706
|
-
};
|
|
1707
|
-
};
|
|
1708
|
-
|
|
1709
|
-
type Dog = {
|
|
1710
|
-
info: {
|
|
1711
|
-
name: string;
|
|
1712
|
-
type: 'dog';
|
|
1713
|
-
dogType: string;
|
|
1714
|
-
};
|
|
1715
|
-
};
|
|
1716
|
-
|
|
1717
|
-
function displayPetInfo(petInfo: (Cat | Dog)['info']) {
|
|
1718
|
-
// typeof petInfo =>
|
|
1719
|
-
// {
|
|
1720
|
-
// name: string;
|
|
1721
|
-
// type: 'cat';
|
|
1722
|
-
// catType: string; // Needn't care about this field, because it's not a common pet info field.
|
|
1723
|
-
// } | {
|
|
1724
|
-
// name: string;
|
|
1725
|
-
// type: 'dog';
|
|
1726
|
-
// dogType: string; // Needn't care about this field, because it's not a common pet info field.
|
|
1727
|
-
// }
|
|
1728
|
-
|
|
1729
|
-
// petInfo type is complex and have some needless fields
|
|
1730
|
-
|
|
1731
|
-
console.log('name: ', petInfo.name);
|
|
1732
|
-
console.log('type: ', petInfo.type);
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
|
-
function displayPetInfo(petInfo: SharedUnionFieldsDeep<Cat | Dog>['info']) {
|
|
1736
|
-
// typeof petInfo =>
|
|
1737
|
-
// {
|
|
1738
|
-
// name: string;
|
|
1739
|
-
// type: 'cat' | 'dog';
|
|
1740
|
-
// }
|
|
1741
|
-
|
|
1742
|
-
// petInfo type is simple and clear
|
|
1751
|
+
type Numbers = 1 | 2 | 3;
|
|
1752
|
+
type NumbersTuple = UnionToTuple<Numbers>;
|
|
1753
|
+
//=> [1, 2, 3]
|
|
1754
|
+
```
|
|
1743
1755
|
|
|
1744
|
-
|
|
1745
|
-
console.log('type: ', petInfo.type);
|
|
1746
|
-
}
|
|
1756
|
+
@example
|
|
1747
1757
|
```
|
|
1758
|
+
import type {UnionToTuple} from 'type-fest';
|
|
1748
1759
|
|
|
1749
|
-
|
|
1760
|
+
const pets = {
|
|
1761
|
+
dog: '🐶',
|
|
1762
|
+
cat: '🐱',
|
|
1763
|
+
snake: '🐍',
|
|
1764
|
+
};
|
|
1750
1765
|
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
*/
|
|
1754
|
-
type SharedUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions = {recurseIntoArrays: false}> =
|
|
1755
|
-
// `Union extends` will convert `Union`
|
|
1756
|
-
// to a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
|
|
1757
|
-
// But this is not what we want, so we need to wrap `Union` with `[]` to prevent it.
|
|
1758
|
-
[Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
|
|
1759
|
-
? Union
|
|
1760
|
-
: [Union] extends [UnknownArray]
|
|
1761
|
-
? Options['recurseIntoArrays'] extends true
|
|
1762
|
-
? SetArrayAccess<SharedArrayUnionFieldsDeep<Union, Options>, IsArrayReadonly<Union>>
|
|
1763
|
-
: Union
|
|
1764
|
-
: [Union] extends [object]
|
|
1765
|
-
? SharedObjectUnionFieldsDeep<Union, Options>
|
|
1766
|
-
: Union;
|
|
1767
|
-
|
|
1768
|
-
/**
|
|
1769
|
-
Same as `SharedUnionFieldsDeep`, but accepts only `object`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
|
|
1770
|
-
*/
|
|
1771
|
-
type SharedObjectUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions> =
|
|
1772
|
-
// `keyof Union` can extract the same key in union type, if there is no same key, return never.
|
|
1773
|
-
keyof Union extends infer Keys
|
|
1774
|
-
? IsNever<Keys> extends false
|
|
1775
|
-
? {
|
|
1776
|
-
[Key in keyof Union]:
|
|
1777
|
-
Union[Key] extends NonRecursiveType
|
|
1778
|
-
? Union[Key]
|
|
1779
|
-
// Remove `undefined` from the union to support optional
|
|
1780
|
-
// fields, then recover `undefined` if union was already undefined.
|
|
1781
|
-
: SharedUnionFieldsDeep<Exclude<Union[Key], undefined>, Options> | (
|
|
1782
|
-
undefined extends Required<Union>[Key] ? undefined : never
|
|
1783
|
-
)
|
|
1784
|
-
}
|
|
1785
|
-
: {}
|
|
1786
|
-
: Union;
|
|
1766
|
+
type Pet = keyof typeof pets;
|
|
1767
|
+
//=> 'dog' | 'cat' | 'snake'
|
|
1787
1768
|
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
type SharedArrayUnionFieldsDeep<Union extends UnknownArray, Options extends SharedUnionFieldsDeepOptions> =
|
|
1792
|
-
// Restore the readonly modifier of the array.
|
|
1793
|
-
SetArrayAccess<
|
|
1794
|
-
InternalSharedArrayUnionFieldsDeep<Union, Options>,
|
|
1795
|
-
IsArrayReadonly<Union>
|
|
1796
|
-
>;
|
|
1769
|
+
const petList = Object.keys(pets) as UnionToTuple<Pet>;
|
|
1770
|
+
//=> ['dog', 'cat', 'snake']
|
|
1771
|
+
```
|
|
1797
1772
|
|
|
1798
|
-
|
|
1799
|
-
Internal helper for `SharedArrayUnionFieldsDeep`. Needn't care the `readonly` modifier of arrays.
|
|
1773
|
+
@category Array
|
|
1800
1774
|
*/
|
|
1801
|
-
type
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
> =
|
|
1806
|
-
// We should build a minimum possible length tuple where each element in the tuple exists in the union tuple.
|
|
1807
|
-
IsNever<TupleLength<Union>> extends true
|
|
1808
|
-
// Rule 1: If all the arrays in the union have non-fixed lengths,
|
|
1809
|
-
// like `Array<string> | [number, ...string[]]`
|
|
1810
|
-
// we should build a tuple that is [the_fixed_parts_of_union, ...the_rest_of_union[]].
|
|
1811
|
-
// For example: `InternalSharedArrayUnionFieldsDeep<Array<string> | [number, ...string[]]>`
|
|
1812
|
-
// => `[string | number, ...string[]]`.
|
|
1813
|
-
? ResultTuple['length'] extends UnionMax<StaticPartOfArray<Union>['length']>
|
|
1814
|
-
? [
|
|
1815
|
-
// The fixed-length part of the tuple.
|
|
1816
|
-
...ResultTuple,
|
|
1817
|
-
// The rest of the union.
|
|
1818
|
-
// Due to `ResultTuple` is the maximum possible fixed-length part of the tuple,
|
|
1819
|
-
// so we can use `StaticPartOfArray` to get the rest of the union.
|
|
1820
|
-
...Array<
|
|
1821
|
-
SharedUnionFieldsDeep<VariablePartOfArray<Union>[number], Options>
|
|
1822
|
-
>,
|
|
1823
|
-
]
|
|
1824
|
-
// Build the fixed-length tuple recursively.
|
|
1825
|
-
: InternalSharedArrayUnionFieldsDeep<
|
|
1826
|
-
Union, Options,
|
|
1827
|
-
[...ResultTuple, SharedUnionFieldsDeep<Union[ResultTuple['length']], Options>]
|
|
1828
|
-
>
|
|
1829
|
-
// Rule 2: If at least one of the arrays in the union have fixed lengths,
|
|
1830
|
-
// like `Array<string> | [number, string]`,
|
|
1831
|
-
// we should build a tuple of the smallest possible length to ensure any
|
|
1832
|
-
// item in the result tuple exists in the union tuple.
|
|
1833
|
-
// For example: `InternalSharedArrayUnionFieldsDeep<Array<string> | [number, string]>`
|
|
1834
|
-
// => `[string | number, string]`.
|
|
1835
|
-
: ResultTuple['length'] extends UnionMin<TupleLength<Union>>
|
|
1836
|
-
? ResultTuple
|
|
1837
|
-
// As above, build tuple recursively.
|
|
1838
|
-
: InternalSharedArrayUnionFieldsDeep<
|
|
1839
|
-
Union, Options,
|
|
1840
|
-
[...ResultTuple, SharedUnionFieldsDeep<Union[ResultTuple['length']], Options>]
|
|
1841
|
-
>;
|
|
1775
|
+
type UnionToTuple<T, L = LastOfUnion<T>> =
|
|
1776
|
+
IsNever<T> extends false
|
|
1777
|
+
? [...UnionToTuple<Exclude<T, L>>, L]
|
|
1778
|
+
: [];
|
|
1842
1779
|
|
|
1843
1780
|
/**
|
|
1844
1781
|
Omit properties from a deeply-nested object.
|
|
@@ -1924,11 +1861,19 @@ type AddressInfo = OmitDeep<Info1, 'address.1.foo'>;
|
|
|
1924
1861
|
*/
|
|
1925
1862
|
type OmitDeep<T, PathUnion extends LiteralUnion<Paths<T>, string>> =
|
|
1926
1863
|
SimplifyDeep<
|
|
1927
|
-
|
|
1928
|
-
{[P in PathUnion]: OmitDeepWithOnePath<T, P>}[PathUnion]
|
|
1929
|
-
>,
|
|
1864
|
+
OmitDeepHelper<T, UnionToTuple<PathUnion>>,
|
|
1930
1865
|
UnknownArray>;
|
|
1931
1866
|
|
|
1867
|
+
/**
|
|
1868
|
+
Internal helper for {@link OmitDeep}.
|
|
1869
|
+
|
|
1870
|
+
Recursively transforms `T` by applying {@link OmitDeepWithOnePath} for each path in `PathTuple`.
|
|
1871
|
+
*/
|
|
1872
|
+
type OmitDeepHelper<T, PathTuple extends UnknownArray> =
|
|
1873
|
+
PathTuple extends [infer Path, ...infer RestPaths]
|
|
1874
|
+
? OmitDeepHelper<OmitDeepWithOnePath<T, Path & (string | number)>, RestPaths>
|
|
1875
|
+
: T;
|
|
1876
|
+
|
|
1932
1877
|
/**
|
|
1933
1878
|
Omit one path from the given object/array.
|
|
1934
1879
|
*/
|
|
@@ -2016,6 +1961,41 @@ type StringKeysOfFoo = StringKeyOf<Foo>;
|
|
|
2016
1961
|
*/
|
|
2017
1962
|
type StringKeyOf<BaseType> = `${Extract<keyof BaseType, string | number>}`;
|
|
2018
1963
|
|
|
1964
|
+
/**
|
|
1965
|
+
Split options.
|
|
1966
|
+
|
|
1967
|
+
@see {@link Split}
|
|
1968
|
+
*/
|
|
1969
|
+
type SplitOptions = {
|
|
1970
|
+
/**
|
|
1971
|
+
When enabled, instantiations with non-literal string types (e.g., `string`, `Uppercase<string>`, `on${string}`) simply return back `string[]` without performing any splitting, as the exact structure cannot be statically determined.
|
|
1972
|
+
|
|
1973
|
+
Note: In the future, this option might be enabled by default, so if you currently rely on this being disabled, you should consider explicitly enabling it.
|
|
1974
|
+
|
|
1975
|
+
@default false
|
|
1976
|
+
|
|
1977
|
+
@example
|
|
1978
|
+
```ts
|
|
1979
|
+
type Example1 = Split<`foo.${string}.bar`, '.', {strictLiteralChecks: false}>;
|
|
1980
|
+
//=> ['foo', string, 'bar']
|
|
1981
|
+
|
|
1982
|
+
type Example2 = Split<`foo.${string}`, '.', {strictLiteralChecks: true}>;
|
|
1983
|
+
//=> string[]
|
|
1984
|
+
|
|
1985
|
+
type Example3 = Split<'foobarbaz', `b${string}`, {strictLiteralChecks: false}>;
|
|
1986
|
+
//=> ['foo', 'r', 'z']
|
|
1987
|
+
|
|
1988
|
+
type Example4 = Split<'foobarbaz', `b${string}`, {strictLiteralChecks: true}>;
|
|
1989
|
+
//=> string[]
|
|
1990
|
+
```
|
|
1991
|
+
*/
|
|
1992
|
+
strictLiteralChecks?: boolean;
|
|
1993
|
+
};
|
|
1994
|
+
|
|
1995
|
+
type DefaultSplitOptions = {
|
|
1996
|
+
strictLiteralChecks: false;
|
|
1997
|
+
};
|
|
1998
|
+
|
|
2019
1999
|
/**
|
|
2020
2000
|
Represents an array of strings split using a given character or character set.
|
|
2021
2001
|
|
|
@@ -2034,17 +2014,37 @@ let array: Item[];
|
|
|
2034
2014
|
array = split(items, ',');
|
|
2035
2015
|
```
|
|
2036
2016
|
|
|
2017
|
+
@see {@link SplitOptions}
|
|
2018
|
+
|
|
2037
2019
|
@category String
|
|
2038
2020
|
@category Template literal
|
|
2039
2021
|
*/
|
|
2040
2022
|
type Split<
|
|
2041
2023
|
S extends string,
|
|
2042
2024
|
Delimiter extends string,
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
:
|
|
2046
|
-
|
|
2047
|
-
|
|
2025
|
+
Options extends SplitOptions = {},
|
|
2026
|
+
> = SplitHelper<S, Delimiter, {
|
|
2027
|
+
strictLiteralChecks: Options['strictLiteralChecks'] extends boolean ? Options['strictLiteralChecks'] : DefaultSplitOptions['strictLiteralChecks'];
|
|
2028
|
+
}>;
|
|
2029
|
+
|
|
2030
|
+
type SplitHelper<
|
|
2031
|
+
S extends string,
|
|
2032
|
+
Delimiter extends string,
|
|
2033
|
+
Options extends Required<SplitOptions>,
|
|
2034
|
+
Accumulator extends string[] = [],
|
|
2035
|
+
> = S extends string // For distributing `S`
|
|
2036
|
+
? Delimiter extends string // For distributing `Delimeter`
|
|
2037
|
+
// If `strictLiteralChecks` is `false` OR `S` and `Delimiter` both are string literals, then perform the split
|
|
2038
|
+
? Or<Not<Options['strictLiteralChecks']>, And<IsStringLiteral<S>, IsStringLiteral<Delimiter>>> extends true
|
|
2039
|
+
? S extends `${infer Head}${Delimiter}${infer Tail}`
|
|
2040
|
+
? SplitHelper<Tail, Delimiter, Options, [...Accumulator, Head]>
|
|
2041
|
+
: Delimiter extends ''
|
|
2042
|
+
? Accumulator
|
|
2043
|
+
: [...Accumulator, S]
|
|
2044
|
+
// Otherwise, return `string[]`
|
|
2045
|
+
: string[]
|
|
2046
|
+
: never // Should never happen
|
|
2047
|
+
: never; // Should never happen
|
|
2048
2048
|
|
|
2049
2049
|
type GetOptions = {
|
|
2050
2050
|
/**
|
|
@@ -2247,7 +2247,7 @@ type Get<
|
|
|
2247
2247
|
BaseType,
|
|
2248
2248
|
Path extends
|
|
2249
2249
|
| readonly string[]
|
|
2250
|
-
| LiteralStringUnion<ToString<Paths<BaseType, {bracketNotation: false}> | Paths<BaseType, {bracketNotation: true}>>>,
|
|
2250
|
+
| LiteralStringUnion<ToString<Paths<BaseType, {bracketNotation: false; maxRecursionDepth: 2}> | Paths<BaseType, {bracketNotation: true; maxRecursionDepth: 2}>>>,
|
|
2251
2251
|
Options extends GetOptions = {}> =
|
|
2252
2252
|
GetWithPath<BaseType, Path extends string ? ToPath<Path> : Path, Options>;
|
|
2253
2253
|
|