Skip to content
This repository was archived by the owner on Sep 27, 2023. It is now read-only.

Commit 10a138d

Browse files
committed
Merge branch 'common-fields-unions' of https://github.com/ktosiek/relay-compiler-language-typescript into ktosiek-common-fields-unions
2 parents 191e4ab + 4c2fbf8 commit 10a138d

File tree

3 files changed

+398
-234
lines changed

3 files changed

+398
-234
lines changed

src/TypeScriptGenerator.ts

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ function selectionsToAST(
9393
state: State,
9494
refTypeName?: string
9595
): ts.TypeNode {
96-
const baseFields = new Map();
96+
const baseFields = new Map<string, Selection>();
9797
const byConcreteType: { [type: string]: Selection[] } = {};
9898

9999
flattenArray(selections).forEach(selection => {
@@ -112,26 +112,21 @@ function selectionsToAST(
112112
});
113113

114114
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+
}
115125

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.
135130
const otherProp = readOnlyObjectTypeProperty(
136131
"__typename",
137132
ts.createLiteralTypeNode(ts.createLiteral("%other"))
@@ -144,44 +139,51 @@ function selectionsToAST(
144139
true
145140
);
146141
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);
167142
}
168143

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)
184163
);
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+
}
185187
}
186188

187189
// We don't have exact object types in typescript.

0 commit comments

Comments
 (0)