11import type { StaticPartOfArray , VariablePartOfArray , NonRecursiveType , ToString , IsNumberLike , ApplyDefaultOptions } from './internal/index.d.ts' ;
22import type { IsAny } from './is-any.d.ts' ;
33import type { UnknownArray } from './unknown-array.d.ts' ;
4- import type { Subtract } from './subtract.d.ts' ;
54import type { GreaterThan } from './greater-than.d.ts' ;
65import type { IsNever } from './is-never.d.ts' ;
6+ import type { Sum } from './sum.d.ts' ;
7+ import type { And } from './and.d.ts' ;
78
89/**
910Paths options.
@@ -190,21 +191,21 @@ open('listB.1'); // TypeError. Because listB only has one element.
190191*/
191192export type Paths < T , Options extends PathsOptions = { } > = _Paths < T , ApplyDefaultOptions < PathsOptions , DefaultPathsOptions , Options > > ;
192193
193- type _Paths < T , Options extends Required < PathsOptions > > =
194+ type _Paths < T , Options extends Required < PathsOptions > , CurrentDepth extends number = 0 > =
194195 T extends NonRecursiveType | ReadonlyMap < unknown , unknown > | ReadonlySet < unknown >
195196 ? never
196197 : IsAny < T > extends true
197198 ? never
198199 : T extends UnknownArray
199200 ? number extends T [ 'length' ]
200201 // We need to handle the fixed and non-fixed index part of the array separately.
201- ? InternalPaths < StaticPartOfArray < T > , Options > | InternalPaths < Array < VariablePartOfArray < T > [ number ] > , Options >
202- : InternalPaths < T , Options >
202+ ? InternalPaths < StaticPartOfArray < T > , Options , CurrentDepth > | InternalPaths < Array < VariablePartOfArray < T > [ number ] > , Options , CurrentDepth >
203+ : InternalPaths < T , Options , CurrentDepth >
203204 : T extends object
204- ? InternalPaths < T , Options >
205+ ? InternalPaths < T , Options , CurrentDepth >
205206 : never ;
206207
207- type InternalPaths < T , Options extends Required < PathsOptions > > =
208+ type InternalPaths < T , Options extends Required < PathsOptions > , CurrentDepth extends number > =
208209 Options [ 'maxRecursionDepth' ] extends infer MaxDepth extends number
209210 ? Required < T > extends infer T
210211 ? T extends readonly [ ]
@@ -215,19 +216,17 @@ type InternalPaths<T, Options extends Required<PathsOptions>> =
215216 [ Key in keyof T ] :
216217 Key extends string | number // Limit `Key` to string or number.
217218 ? (
218- Options [ 'bracketNotation' ] extends true
219- ? IsNumberLike < Key > extends true
220- ? `[${Key } ]`
221- : ( Key | ToString < Key > )
222- : Options [ 'bracketNotation' ] extends false
219+ And < Options [ 'bracketNotation' ] , IsNumberLike < Key > > extends true
220+ ? `[${Key } ]`
223221 // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
224- ? ( Key | ToString < Key > )
225- : never
222+ : CurrentDepth extends 0
223+ ? Key | ToString < Key >
224+ : `.${( Key | ToString < Key > ) } `
226225 ) extends infer TranformedKey extends string | number ?
227226 // 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
228227 // 2. If style is 'a.0.b', transform 'Key' to `${Key}` | Key
229228 | ( ( Options [ 'leavesOnly' ] extends true
230- ? MaxDepth extends 0
229+ ? MaxDepth extends CurrentDepth
231230 ? TranformedKey
232231 : T [ Key ] extends infer Value
233232 ? ( Value extends readonly [ ] | NonRecursiveType | ReadonlyMap < unknown , unknown > | ReadonlySet < unknown >
@@ -238,36 +237,16 @@ type InternalPaths<T, Options extends Required<PathsOptions>> =
238237 : never
239238 : TranformedKey
240239 ) extends infer _TransformedKey
241- // If `depth` is provided, the condition becomes truthy only when it reaches `0 `.
240+ // If `depth` is provided, the condition becomes truthy only when it reaches `CurrentDepth `.
242241 // Otherwise, since `depth` defaults to `number`, the condition is always truthy, returning paths at all depths.
243- ? 0 extends Options [ 'depth' ]
242+ ? CurrentDepth extends Options [ 'depth' ]
244243 ? _TransformedKey
245244 : never
246245 : never )
247246 | (
248247 // Recursively generate paths for the current key
249- GreaterThan < MaxDepth , 0 > extends true // Limit the depth to prevent infinite recursion
250- ? _Paths < T [ Key ] ,
251- {
252- bracketNotation : Options [ 'bracketNotation' ] ;
253- maxRecursionDepth : Subtract < MaxDepth , 1 > ;
254- leavesOnly : Options [ 'leavesOnly' ] ;
255- depth : Subtract < Options [ 'depth' ] , 1 > ;
256- } > extends infer SubPath
257- ? SubPath extends string | number
258- ? (
259- Options [ 'bracketNotation' ] extends true
260- ? SubPath extends `[${any } ]` | `[${any } ]${string } `
261- ? `${TranformedKey } ${SubPath } ` // If next node is number key like `[3]`, no need to add `.` before it.
262- : `${TranformedKey } .${SubPath } `
263- : never
264- ) | (
265- Options [ 'bracketNotation' ] extends false
266- ? `${TranformedKey } .${SubPath } `
267- : never
268- )
269- : never
270- : never
248+ GreaterThan < MaxDepth , CurrentDepth > extends true // Limit the depth to prevent infinite recursion
249+ ? `${TranformedKey } ${_Paths < T [ Key ] , Options , Sum < CurrentDepth , 1 > > & ( string | number ) } `
271250 : never
272251 )
273252 : never
0 commit comments