@@ -93,7 +93,7 @@ function selectionsToAST(
93
93
state : State ,
94
94
refTypeName ?: string
95
95
) : ts . TypeNode {
96
- const baseFields = new Map ( ) ;
96
+ const baseFields = new Map < string , Selection > ( ) ;
97
97
const byConcreteType : { [ type : string ] : Selection [ ] } = { } ;
98
98
99
99
flattenArray ( selections ) . forEach ( selection => {
@@ -112,26 +112,21 @@ function selectionsToAST(
112
112
} ) ;
113
113
114
114
const types : ts . PropertySignature [ ] [ ] = [ ] ;
115
+ const discriminators = Array . from ( baseFields . values ( ) ) . filter (
116
+ isTypenameSelection
117
+ ) ;
118
+ for ( const concreteType in byConcreteType ) {
119
+ types . push (
120
+ groupRefs ( [ ...discriminators , ...byConcreteType [ concreteType ] ] ) . map (
121
+ selection => makeProp ( selection , state , concreteType )
122
+ )
123
+ ) ;
124
+ }
115
125
116
- if (
117
- Object . keys ( byConcreteType ) . length &&
118
- onlySelectsTypename ( Array . from ( baseFields . values ( ) ) ) &&
119
- ( hasTypenameSelection ( Array . from ( baseFields . values ( ) ) ) ||
120
- Object . keys ( byConcreteType ) . every ( type =>
121
- hasTypenameSelection ( byConcreteType [ type ] )
122
- ) )
123
- ) {
124
- for ( const concreteType in byConcreteType ) {
125
- types . push (
126
- groupRefs ( [
127
- ...Array . from ( baseFields . values ( ) ) ,
128
- ...byConcreteType [ concreteType ]
129
- ] ) . map ( selection => makeProp ( selection , state , concreteType ) )
130
- ) ;
131
- }
132
- // It might be some other type than the listed concrete types. Ideally, we
133
- // would set the type to diff(string, set of listed concrete types), but
134
- // this doesn't exist in Flow at the time.
126
+ if ( types . length ) {
127
+ // It might be some other type than the listed concrete types.
128
+ // Ideally, we would set the type to Exclude<string, set of listed concrete types>,
129
+ // but this doesn't work with TypeScript's discriminated unions.
135
130
const otherProp = readOnlyObjectTypeProperty (
136
131
"__typename" ,
137
132
ts . createLiteralTypeNode ( ts . createLiteral ( "%other" ) )
@@ -144,44 +139,51 @@ function selectionsToAST(
144
139
true
145
140
) ;
146
141
types . push ( [ otherPropWithComment ] ) ;
147
- } else {
148
- let selectionMap = selectionsToMap ( Array . from ( baseFields . values ( ) ) ) ;
149
- for ( const concreteType in byConcreteType ) {
150
- selectionMap = mergeSelections (
151
- selectionMap ,
152
- selectionsToMap (
153
- byConcreteType [ concreteType ] . map ( sel => ( {
154
- ...sel ,
155
- conditional : true
156
- } ) )
157
- )
158
- ) ;
159
- }
160
- const selectionMapValues = groupRefs ( Array . from ( selectionMap . values ( ) ) ) . map (
161
- sel =>
162
- isTypenameSelection ( sel ) && sel . concreteType
163
- ? makeProp ( { ...sel , conditional : false } , state , sel . concreteType )
164
- : makeProp ( sel , state )
165
- ) ;
166
- types . push ( selectionMapValues ) ;
167
142
}
168
143
169
- return ts . createUnionTypeNode (
170
- types . map ( props => {
171
- if ( refTypeName ) {
172
- props . push (
173
- readOnlyObjectTypeProperty (
174
- REF_TYPE ,
175
- ts . createTypeReferenceNode (
176
- ts . createIdentifier ( refTypeName ) ,
177
- undefined
178
- )
179
- )
180
- ) ;
181
- }
182
- return exactObjectTypeAnnotation ( props ) ;
183
- } )
144
+ let selectionMap = selectionsToMap ( Array . from ( baseFields . values ( ) ) ) ;
145
+ for ( const concreteType in byConcreteType ) {
146
+ selectionMap = mergeSelections (
147
+ selectionMap ,
148
+ selectionsToMap (
149
+ byConcreteType [ concreteType ] . map ( sel => ( {
150
+ ...sel ,
151
+ conditional : true
152
+ } ) )
153
+ )
154
+ ) ;
155
+ }
156
+ const baseProps : ts . PropertySignature [ ] = groupRefs (
157
+ Array . from ( selectionMap . values ( ) )
158
+ ) . map (
159
+ sel =>
160
+ isTypenameSelection ( sel ) && sel . concreteType
161
+ ? makeProp ( { ...sel , conditional : false } , state , sel . concreteType )
162
+ : makeProp ( sel , state )
184
163
) ;
164
+
165
+ if ( refTypeName ) {
166
+ baseProps . push (
167
+ readOnlyObjectTypeProperty (
168
+ REF_TYPE ,
169
+ ts . createTypeReferenceNode ( ts . createIdentifier ( refTypeName ) , undefined )
170
+ )
171
+ ) ;
172
+ }
173
+
174
+ if ( types . length > 0 ) {
175
+ const unionType = ts . createUnionTypeNode (
176
+ types . map ( props => {
177
+ return exactObjectTypeAnnotation ( props ) ;
178
+ } )
179
+ ) ;
180
+ return ts . createIntersectionTypeNode ( [
181
+ exactObjectTypeAnnotation ( baseProps ) ,
182
+ unionType
183
+ ] ) ;
184
+ } else {
185
+ return exactObjectTypeAnnotation ( baseProps ) ;
186
+ }
185
187
}
186
188
187
189
// We don't have exact object types in typescript.
0 commit comments