@@ -3,8 +3,22 @@ import type {EmptyObject} from './empty-object';
33import type { IsAny } from './is-any' ;
44import type { IsNever } from './is-never' ;
55import 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+ } ;
822
923/**
1024Generate 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.
4761@category Object
4862@category Array
4963*/
50- export type Paths < T > = Paths_ < T > ;
51-
52- type Paths_ < T , Depth extends number = 0 > =
64+ export type Paths < T , Options extends PathsOptions = { } > =
5365T extends NonRecursiveType | ReadonlyMap < unknown , unknown > | ReadonlySet < unknown >
5466? never
5567: IsAny < T > extends true
5668? never
5769: T extends UnknownArray
5870? number extends T [ 'length' ]
5971// 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 >
6375: T extends object
64- ? InternalPaths < T , Depth >
76+ ? InternalPaths < T , Options >
6577: never ;
6678
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+ )
8298: 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