1+ // Type definitions using a type mapping approach
2+ type EntityMap = {
3+ Order : {
4+ id : string ;
5+ date : Date ;
6+ total : number ;
7+ } ;
8+ Line : {
9+ id : string ;
10+ quantity : number ;
11+ price : number ;
12+ } ;
13+ Package : {
14+ id : string ;
15+ trackingNumber : string ;
16+ weight : number ;
17+ } ;
18+ Customer : {
19+ id : string ;
20+ name : string ;
21+ email : string ;
22+ } ;
23+ } ;
24+
25+ // Enhanced relation mapping that includes cardinality information
26+ type RelationMap = {
27+ Order : {
28+ lines : { type : 'Line' ; isArray : true } ;
29+ customer : { type : 'Customer' ; isArray : false } ;
30+ } ;
31+ Line : {
32+ packages : { type : 'Package' ; isArray : true } ;
33+ order : { type : 'Order' ; isArray : false } ;
34+ } ;
35+ Customer : {
36+ orders : { type : 'Order' ; isArray : true } ;
37+ } ;
38+ Package : { } ;
39+ } ;
40+
41+ // Helper type to extract the entity type from a relation
42+ type RelationEntityType < R > = R extends { type : infer T extends keyof EntityMap } ? T : never ;
43+
44+ // Helper type to determine if a relation is an array
45+ type IsArray < R > = R extends { isArray : infer A extends boolean } ? A : false ;
46+
47+ // Generic deep type resolver
48+ type Depth = [ never , 0 , 1 , 2 , 3 , 4 , 5 ] ;
49+
50+ // RecursiveType generic with improved depth handling
51+ type RecursiveType <
52+ T extends keyof EntityMap ,
53+ D extends number = 5
54+ > = {
55+ // Always include base properties
56+ [ K in keyof EntityMap [ T ] ] : EntityMap [ T ] [ K ] ;
57+ } & ( D extends 0
58+ ? // At max depth, only include base properties (which are already included above)
59+ { }
60+ : // Otherwise include relations with appropriate depth reduction
61+ {
62+ [ K in keyof RelationMap [ T ] ] : IsArray < RelationMap [ T ] [ K ] > extends true
63+ ? RecursiveType <
64+ RelationEntityType < RelationMap [ T ] [ K ] > ,
65+ Depth [ D ]
66+ > [ ]
67+ : RecursiveType <
68+ RelationEntityType < RelationMap [ T ] [ K ] > ,
69+ Depth [ D ]
70+ > ;
71+ } ) ;
72+
73+ // Generate the entity types with relationships resolved to the specified depth
74+ type Order = RecursiveType < 'Order' , 6 > ;
75+
76+ type Line = RecursiveType < 'Line' > ;
77+ type Package = RecursiveType < 'Package' > ;
78+ type Customer = RecursiveType < 'Customer' > ;
79+
80+ // Example usage
81+ function processOrder ( order : Order , line : Line ) {
82+ // Can access nested properties up to depth 5
83+ // const trackingNumber = order.customer.orders[0].lines[0].order.lines[0].packages[0].
84+ // const orderId = order.customer.orders[0].customer.orders[0].lines[0].
85+ line . order . customer . orders [ 0 ] . lines [ 0 ] . packages [ 0 ] .
86+
87+ console . log ( trackingNumber , orderId ) ;
88+ }
89+
90+ // Allow custom depth control per entity type
91+ type OrderWithDepth1 = RecursiveType < 'Order' , 4 > ;
92+
93+ // Example with custom depth
94+ function processOrderWithLimitedDepth ( order : OrderWithDepth1 ) {
95+ // This would work (depth 1)
96+
97+ console . log ( order . customer . id ) ; // Can access base properties at max depth
98+ console . log ( order . customer . name ) ; // Can access base properties at max depth
99+
100+ // This would error - beyond depth 1
101+ // console.log(order.customer.orders[0].id);
102+ }
103+
104+ // Example of creating an instance with this type system
105+ const sampleOrder : Order = {
106+ id : "ORD-123" ,
107+ date : new Date ( ) ,
108+ total : 299.99 ,
109+ customer : {
110+ id : "CUST-456" ,
111+ name : "John Doe" ,
112+ email : "john@example.com" ,
113+ orders : [
114+ /* would be recursive orders */
115+ ]
116+ } ,
117+ lines : [
118+ {
119+ id : "LINE-789" ,
120+ quantity : 2 ,
121+ price : 149.99 ,
122+ order : /* circular reference */ ,
123+ packages : [
124+ {
125+ id : "PKG-101" ,
126+ trackingNumber : "TRK123456789" ,
127+ weight : 1.5
128+ }
129+ ]
130+ }
131+ ]
132+ } ;
0 commit comments