@@ -3,8 +3,22 @@ import type {EmptyObject} from './empty-object';
3
3
import type { IsAny } from './is-any' ;
4
4
import type { IsNever } from './is-never' ;
5
5
import type { UnknownArray } from './unknown-array' ;
6
- import type { Sum } from './sum' ;
7
- import type { LessThan } from './less-than' ;
6
+ import type { Subtract } from './subtract' ;
7
+ import type { GreaterThan } from './greater-than' ;
8
+
9
+ /**
10
+ Paths options.
11
+
12
+ @see {@link Paths }
13
+ */
14
+ export type PathsOptions = {
15
+ /**
16
+ The maximum depth to recurse when searching for paths.
17
+
18
+ @default 10
19
+ */
20
+ maxRecursionDepth ?: number ;
21
+ } ;
8
22
9
23
/**
10
24
Generate a union of all possible paths to properties in the given object.
@@ -47,39 +61,41 @@ open('listB.1'); // TypeError. Because listB only has one element.
47
61
@category Object
48
62
@category Array
49
63
*/
50
- export type Paths < T > = Paths_ < T > ;
51
-
52
- type Paths_ < T , Depth extends number = 0 > =
64
+ export type Paths < T , Options extends PathsOptions = { } > =
53
65
T extends NonRecursiveType | ReadonlyMap < unknown , unknown > | ReadonlySet < unknown >
54
66
? never
55
67
: IsAny < T > extends true
56
68
? never
57
69
: T extends UnknownArray
58
70
? number extends T [ 'length' ]
59
71
// We need to handle the fixed and non-fixed index part of the array separately.
60
- ? InternalPaths < StaticPartOfArray < T > , Depth >
61
- | InternalPaths < Array < VariablePartOfArray < T > [ number ] > , Depth >
62
- : InternalPaths < T , Depth >
72
+ ? InternalPaths < StaticPartOfArray < T > , Options >
73
+ | InternalPaths < Array < VariablePartOfArray < T > [ number ] > , Options >
74
+ : InternalPaths < T , Options >
63
75
: T extends object
64
- ? InternalPaths < T , Depth >
76
+ ? InternalPaths < T , Options >
65
77
: never ;
66
78
67
- export type InternalPaths < _T , Depth extends number = 0 , T = Required < _T > > =
68
- T extends EmptyObject | readonly [ ]
69
- ? never
70
- : {
71
- [ Key in keyof T ] :
72
- Key extends string | number // Limit `Key` to string or number.
73
- // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
74
- ?
75
- | Key
76
- | ToString < Key >
77
- | (
78
- LessThan < Depth , 15 > extends true // Limit the depth to prevent infinite recursion
79
- ? IsNever < Paths_ < T [ Key ] , Sum < Depth , 1 > > > extends false
80
- ? `${Key } .${Paths_ < T [ Key ] , Sum < Depth , 1 > > } `
81
- : never
79
+ type InternalPaths < T , Options extends PathsOptions = { } > =
80
+ ( Options [ 'maxRecursionDepth' ] extends number ? Options [ 'maxRecursionDepth' ] : 10 ) extends infer MaxDepth extends number
81
+ ? Required < T > extends infer T
82
+ ? T extends EmptyObject | readonly [ ]
83
+ ? never
84
+ : {
85
+ [ Key in keyof T ] :
86
+ Key extends string | number // Limit `Key` to string or number.
87
+ // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
88
+ ?
89
+ | Key
90
+ | ToString < Key >
91
+ | (
92
+ GreaterThan < MaxDepth , 0 > extends true // Limit the depth to prevent infinite recursion
93
+ ? IsNever < Paths < T [ Key ] , { maxRecursionDepth : Subtract < MaxDepth , 1 > } > > extends false
94
+ ? `${Key } .${Paths < T [ Key ] , { maxRecursionDepth : Subtract < MaxDepth , 1 > } > } `
95
+ : never
96
+ : never
97
+ )
82
98
: never
83
- )
84
- : never
85
- } [ keyof T & ( T extends UnknownArray ? number : unknown ) ] ;
99
+ } [ keyof T & ( T extends UnknownArray ? number : unknown ) ]
100
+ : never
101
+ : never ;
0 commit comments