1+ import { describe , expectTypeOf , it } from "vitest" ;
2+ import { defineEntity , defineField , defineIdField , Farstorm , OutputType } from "../../src/main" ;
3+
4+ describe ( 'Types: circular references' , ( ) => {
5+ const entityDefinitions = {
6+ 'EntityA' : defineEntity ( {
7+ fields : {
8+ id : defineIdField ( ) ,
9+ name : defineField ( 'string' , false ) ,
10+ a1 : defineField ( 'string' , false ) ,
11+ a2 : defineField ( 'string' , false ) ,
12+ a3 : defineField ( 'string' , false ) ,
13+ a4 : defineField ( 'string' , false ) ,
14+ a5 : defineField ( 'string' , false ) ,
15+ a6 : defineField ( 'string' , false ) ,
16+ a7 : defineField ( 'string' , false ) ,
17+ a8 : defineField ( 'string' , false ) ,
18+ a9 : defineField ( 'string' , false ) ,
19+ a10 : defineField ( 'string' , false ) ,
20+ a11 : defineField ( 'string' , false ) ,
21+ a12 : defineField ( 'string' , false ) ,
22+ a13 : defineField ( 'string' , false ) ,
23+ a14 : defineField ( 'string' , false ) ,
24+ a15 : defineField ( 'string' , false ) ,
25+ a16 : defineField ( 'string' , false ) ,
26+ a17 : defineField ( 'string' , false ) ,
27+ a18 : defineField ( 'string' , false ) ,
28+ a19 : defineField ( 'string' , false ) ,
29+ } ,
30+ oneToMany : {
31+ b : { entity : 'EntityB' , inverse : 'a' } ,
32+ bOther : { entity : 'EntityB' , inverse : 'anotherA' } ,
33+ } ,
34+ } ) ,
35+ 'EntityB' : defineEntity ( {
36+ fields : {
37+ id : defineIdField ( ) ,
38+ name : defineField ( 'string' , false ) ,
39+ b1 : defineField ( 'string' , false ) ,
40+ b2 : defineField ( 'string' , false ) ,
41+ b3 : defineField ( 'string' , false ) ,
42+ b4 : defineField ( 'string' , false ) ,
43+ b5 : defineField ( 'string' , false ) ,
44+ b6 : defineField ( 'string' , false ) ,
45+ b7 : defineField ( 'string' , false ) ,
46+ b8 : defineField ( 'string' , false ) ,
47+ b9 : defineField ( 'string' , false ) ,
48+ b10 : defineField ( 'string' , false ) ,
49+ b11 : defineField ( 'string' , false ) ,
50+ b12 : defineField ( 'string' , false ) ,
51+ b13 : defineField ( 'string' , false ) ,
52+ b14 : defineField ( 'string' , false ) ,
53+ b15 : defineField ( 'string' , false ) ,
54+ b16 : defineField ( 'string' , false ) ,
55+ b17 : defineField ( 'string' , false ) ,
56+ b18 : defineField ( 'string' , false ) ,
57+ b19 : defineField ( 'string' , false ) ,
58+ } ,
59+ manyToOne : {
60+ a : { entity : 'EntityA' , nullable : false } ,
61+ anotherA : { entity : 'EntityA' , nullable : true } ,
62+ } ,
63+ } ) ,
64+ } ;
65+
66+ it ( 'should still keep types even if recursing deeply' , async ( ) => {
67+ type OrmOutput < N extends keyof typeof entityDefinitions > = OutputType < typeof entityDefinitions , typeof entityDefinitions [ N ] > ;
68+
69+ type BaseA = OrmOutput < 'EntityA' > ;
70+ type BaseB = OrmOutput < 'EntityB' > ;
71+
72+ type AtoB1 = Awaited < BaseA [ 'b' ] > [ number ] ;
73+ type BtoA1 = Awaited < BaseB [ 'a' ] > ;
74+
75+ expectTypeOf < AtoB1 > ( ) . toEqualTypeOf < BaseB > ( ) ;
76+ expectTypeOf < BtoA1 > ( ) . toEqualTypeOf < BaseA > ( ) ;
77+
78+ type AtoBOther = Awaited < BaseA [ 'bOther' ] > [ number ] ;
79+ type BtoAOther = NonNullable < Awaited < BaseB [ 'anotherA' ] > > ;
80+
81+ expectTypeOf < AtoBOther > ( ) . toEqualTypeOf < BaseB > ( ) ;
82+ expectTypeOf < BtoAOther > ( ) . toEqualTypeOf < BaseA > ( ) ;
83+
84+ type GetB < T extends BaseA > = Awaited < T [ 'b' ] > [ number ] ;
85+ type GetA < T extends BaseB > = Awaited < T [ 'a' ] > ;
86+ type DeepChainAtoB = GetB < GetA < GetB < GetA < GetB < GetA < GetB < GetA < GetB < GetA < GetB < GetA < GetB < GetA < GetB < GetA < GetB < BaseA > > > > > > > > > > > > > > > > > ;
87+ expectTypeOf < DeepChainAtoB > ( ) . toEqualTypeOf < BaseB > ( ) ;
88+ } ) ;
89+ } ) ;
0 commit comments