diff --git a/src/TypeScriptGenerator.ts b/src/TypeScriptGenerator.ts index 32685733..5acee477 100644 --- a/src/TypeScriptGenerator.ts +++ b/src/TypeScriptGenerator.ts @@ -9,6 +9,7 @@ import { TypeGenerator, TypeID, } from "relay-compiler"; +import { UnionTypeID } from "relay-compiler/lib/core/Schema"; import { TypeGeneratorOptions } from "relay-compiler/lib/language/RelayLanguagePluginInterface"; import * as FlattenTransform from "relay-compiler/lib/transforms/FlattenTransform"; import * as MaskTransform from "relay-compiler/lib/transforms/MaskTransform"; @@ -127,7 +128,8 @@ function makeProp( selection: Selection, state: State, unmasked: boolean, - concreteType?: string + concreteType?: string, + unionType?: UnionTypeID ): ts.PropertySignature { let { value } = selection; @@ -137,6 +139,16 @@ function makeProp( value = ts.factory.createLiteralTypeNode( ts.factory.createStringLiteral(concreteType) ); + } else if (schemaName === "__typename" && unionType) { + value = ts.factory.createUnionTypeNode( + schema + .getUnionTypes(unionType) + .map((type) => + ts.factory.createLiteralTypeNode( + ts.factory.createStringLiteral(type.name) + ) + ) + ); } else if (nodeType) { value = transformScalarType( schema, @@ -144,6 +156,7 @@ function makeProp( state, selectionsToAST( schema, + nodeType, [Array.from(nullThrows(nodeSelections).values())], state, unmasked @@ -160,29 +173,41 @@ function makeProp( const isTypenameSelection = (selection: Selection) => selection.schemaName === "__typename"; +const isFragmentSelection = (selection: Selection) => !!selection.ref; + const hasTypenameSelection = (selections: Selection[]) => selections.some(isTypenameSelection); -const onlySelectsTypename = (selections: Selection[]) => - selections.every(isTypenameSelection); +const onlySelectsFragments = (selections: Selection[]) => + selections.every(isFragmentSelection); function selectionsToAST( schema: Schema, + nodeType: TypeID | null, selections: ReadonlyArray>, state: State, unmasked: boolean, fragmentTypeName?: string ) { const baseFields = new Map(); + const baseFragments = new Map(); const byConcreteType: { [type: string]: Selection[] } = {}; flattenArray(selections).forEach((selection) => { - const { concreteType } = selection; + let { concreteType } = selection; + + // If the concrete type matches the node type, we can add this to the base fields + // and fragments instead. + if (nodeType && concreteType && nodeType.name === concreteType) { + concreteType = undefined; + } if (concreteType) { byConcreteType[concreteType] = byConcreteType[concreteType] || []; byConcreteType[concreteType].push(selection); + } else if (selection.ref) { + baseFragments.set(selection.ref, selection); } else { const previousSel = baseFields.get(selection.key); @@ -193,23 +218,45 @@ function selectionsToAST( } }); - const types: ts.PropertySignature[][] = []; + // If there are any concrete types that only select fragments, move those + // fragments to the base fragments instead. + for (const concreteType in byConcreteType) { + const concreteTypeSelections = byConcreteType[concreteType]; + if (onlySelectsFragments(concreteTypeSelections)) { + concreteTypeSelections.forEach((selection) => + baseFragments.set(selection.ref!, selection) + ); - if ( + delete byConcreteType[concreteType]; + } + } + + const concreteTypes: ts.PropertySignature[][] = []; + const typeFieldsPresentForUnion = Object.keys(byConcreteType).length > 0 && - onlySelectsTypename(Array.from(baseFields.values())) && (hasTypenameSelection(Array.from(baseFields.values())) || Object.keys(byConcreteType).every((type) => hasTypenameSelection(byConcreteType[type]) - )) - ) { + )); + + if (typeFieldsPresentForUnion) { const typenameAliases = new Set(); for (const concreteType in byConcreteType) { - types.push( + const concreteTypeSelections = byConcreteType[concreteType]; + const concreteTypeSelectionsNames = concreteTypeSelections.map( + (selection) => selection.schemaName + ); + + concreteTypes.push( groupRefs([ - ...Array.from(baseFields.values()), - ...byConcreteType[concreteType], + // Deduplicate any fields also selected on the concrete type. + ...Array.from(baseFields.values()).filter( + (selection) => + isTypenameSelection(selection) && + !concreteTypeSelectionsNames.includes(selection.schemaName) + ), + ...concreteTypeSelections, ]).map((selection) => { if (selection.schemaName === "__typename") { typenameAliases.add(selection.key); @@ -219,32 +266,57 @@ function selectionsToAST( ); } - // It might be some other type then the listed concrete types. Ideally, we - // would set the type to diff(string, set of listed concrete types), but - // this doesn't exist in Flow at the time. - types.push( - Array.from(typenameAliases).map((typenameAlias) => { - const otherProp = objectTypeProperty( - typenameAlias, - ts.factory.createLiteralTypeNode( - ts.factory.createStringLiteral("%other") - ) - ); + // It might be some other type then the listed concrete types. We try to + // figure out which types remain here. + let possibleTypesLeft: TypeID[] | null = null; + const innerType = + nodeType !== null ? schema.getNullableType(nodeType) : null; + if ( + innerType !== null && + (schema.isUnion(innerType) || schema.isInterface(innerType)) + ) { + const typesSeen = Object.keys(byConcreteType); + possibleTypesLeft = Array.from(schema.getPossibleTypes(innerType)).filter( + (type) => !typesSeen.includes(type.name) + ); + } - const otherPropWithComment = ts.addSyntheticLeadingComment( - otherProp, - ts.SyntaxKind.MultiLineCommentTrivia, - "This will never be '%other', but we need some\n" + - "value in case none of the concrete values match.", - true - ); + // If we don't know which types are left we set the value to "%other", + // otherwise return a union of type names. + if (!possibleTypesLeft || possibleTypesLeft.length > 0) { + concreteTypes.push( + Array.from(typenameAliases).map((typenameAlias) => { + const otherProp = objectTypeProperty( + typenameAlias, + possibleTypesLeft + ? ts.createUnionTypeNode( + possibleTypesLeft.map((type) => + ts.createLiteralTypeNode(ts.createLiteral(type.name)) + ) + ) + : ts.createLiteralTypeNode(ts.createLiteral("%other")) + ); - return otherPropWithComment; - }) - ); - } else { - let selectionMap = selectionsToMap(Array.from(baseFields.values())); + if (possibleTypesLeft) { + return otherProp; + } + + const otherPropWithComment = ts.addSyntheticLeadingComment( + otherProp, + ts.SyntaxKind.MultiLineCommentTrivia, + "This will never be '%other', but we need some\n" + + "value in case none of the concrete values match.", + true + ); + + return otherPropWithComment; + }) + ); + } + } + let selectionMap = selectionsToMap(Array.from(baseFields.values())); + if (!typeFieldsPresentForUnion) { for (const concreteType in byConcreteType) { selectionMap = mergeSelections( selectionMap, @@ -256,48 +328,63 @@ function selectionsToAST( ) ); } - - const selectionMapValues = groupRefs(Array.from(selectionMap.values())).map( - (sel) => - isTypenameSelection(sel) && sel.concreteType - ? makeProp( - schema, - { - ...sel, - conditional: false, - }, - state, - unmasked, - sel.concreteType - ) - : makeProp(schema, sel, state, unmasked) - ); - - types.push(selectionMapValues); } - const typeElements = types.map((props) => { - if (fragmentTypeName) { - props.push( - objectTypeProperty( - REF_TYPE, - ts.factory.createLiteralTypeNode( - ts.factory.createStringLiteral(fragmentTypeName) - ) + const baseTypeProps = groupRefs( + [ + ...Array.from(baseFragments.values()), + ...Array.from(selectionMap.values()), + ].filter( + (selection) => + !typeFieldsPresentForUnion || !isTypenameSelection(selection) + ) + ).map((sel) => + isTypenameSelection(sel) && + (sel.concreteType || + (nodeType && schema.isUnion(schema.getNullableType(nodeType)))) + ? makeProp( + schema, + { + ...sel, + conditional: false, + }, + state, + unmasked, + sel.concreteType, + nodeType && schema.isUnion(schema.getNullableType(nodeType)) + ? schema.getNullableType(nodeType) + : undefined ) - ); - } + : makeProp(schema, sel, state, unmasked) + ); - return unmasked + if (fragmentTypeName) { + baseTypeProps.push( + objectTypeProperty( + REF_TYPE, + ts.factory.createLiteralTypeNode( + ts.factory.createStringLiteral(fragmentTypeName) + ) + ) + ); + } + + const propsToObject = (props: ts.PropertySignature[]) => + unmasked ? ts.factory.createTypeLiteralNode(props) : exactObjectTypeAnnotation(props); - }); - if (typeElements.length === 1) { - return typeElements[0]; + const baseType = propsToObject(baseTypeProps); + if (concreteTypes.length === 0) { + return baseType; } - return ts.factory.createUnionTypeNode(typeElements); + const unionType = ts.factory.createUnionTypeNode( + concreteTypes.map(propsToObject) + ); + return baseTypeProps.length > 0 + ? ts.factory.createIntersectionTypeNode([unionType, baseType]) + : unionType; } // We don't have exact object types in typescript. @@ -446,6 +533,7 @@ function createVisitor( `${node.name}Response`, selectionsToAST( schema, + null, /* $FlowFixMe: selections have already been transformed */ (node.selections as any) as ReadonlyArray>, state, @@ -573,6 +661,7 @@ function createVisitor( const unmasked = node.metadata != null && node.metadata.mask === false; const baseType = selectionsToAST( schema, + node.type, selections, state, unmasked, @@ -848,21 +937,7 @@ function appendLocal3DPayload( if (moduleImport) { // Generate an extra opaque type for client 3D fields state.runtimeImports.add("Local3DPayload"); - types.push( - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("Local3DPayload"), - [ - stringLiteralTypeAnnotation(moduleImport.documentName!), - exactObjectTypeAnnotation( - selections - .filter((sel) => sel.schemaName !== "js") - .map((selection) => - makeRawResponseProp(schema, selection, state, currentType) - ) - ), - ] - ) - ); + types.push(); } } diff --git a/test/__snapshots__/TypeScriptGenerator-test.ts.snap b/test/__snapshots__/TypeScriptGenerator-test.ts.snap index e8fa236a..159c8313 100644 --- a/test/__snapshots__/TypeScriptGenerator-test.ts.snap +++ b/test/__snapshots__/TypeScriptGenerator-test.ts.snap @@ -124,9 +124,7 @@ export type ConcreateTypes = { readonly __typename: "User"; readonly name: string | null; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "ExtraUser"; }) | null; readonly " $refType": "ConcreateTypes"; }; @@ -142,11 +140,6 @@ import { FragmentRefs } from "relay-runtime"; export type PictureFragment = { readonly __typename: "Image"; readonly " $refType": "PictureFragment"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "PictureFragment"; }; export type PictureFragment$data = PictureFragment; export type PictureFragment$key = { @@ -173,11 +166,6 @@ import { FragmentRefs } from "relay-runtime"; export type PageFragment = { readonly __typename: "Page"; readonly " $refType": "PageFragment"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "PageFragment"; }; export type PageFragment$data = PageFragment; export type PageFragment$key = { @@ -191,11 +179,6 @@ import { FragmentRefs } from "relay-runtime"; export type UserFrag1 = { readonly __typename: "User"; readonly " $refType": "UserFrag1"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "UserFrag1"; }; export type UserFrag1$data = UserFrag1; export type UserFrag1$key = { @@ -209,11 +192,6 @@ import { FragmentRefs } from "relay-runtime"; export type UserFrag2 = { readonly __typename: "User"; readonly " $refType": "UserFrag2"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "UserFrag2"; }; export type UserFrag2$data = UserFrag2; export type UserFrag2$key = { @@ -369,11 +347,6 @@ import { FragmentRefs } from "relay-runtime"; export type SomeFragment = { readonly __typename: "User"; readonly " $refType": "SomeFragment"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "SomeFragment"; }; export type SomeFragment$data = SomeFragment; export type SomeFragment$key = { @@ -447,9 +420,7 @@ export type UnionTypeTestResponse = { readonly __typename: "FakeNode"; readonly id: string; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "NonNode"; }) | null; }; export type UnionTypeTest = { @@ -1978,20 +1949,27 @@ export type RelayClientIDFieldQueryResponse = { readonly __typename: string; readonly id: string; } | null; - readonly node: { - readonly __id: string; - readonly __typename: string; - readonly id: string; - readonly commentBody?: { + readonly node: (({ + readonly __typename: "Comment"; + readonly commentBody: (({ + readonly __typename: "PlainCommentBody"; readonly __id: string; - readonly __typename: string; - readonly text?: { + readonly text: { readonly __id: string; readonly __typename: string; readonly text: string | null; } | null; - } | null; - } | null; + } | { + readonly __typename: "MarkdownCommentBody"; + }) & { + readonly __id: string; + }) | null; + } | { + readonly __typename: "Feedback" | "Page" | "PhotoStory" | "Story" | "User"; + }) & { + readonly __id: string; + readonly id: string; + }) | null; }; export type RelayClientIDFieldQuery = { readonly response: RelayClientIDFieldQueryResponse; @@ -2184,9 +2162,7 @@ export type TypenameInsideWithOverlappingFields = { readonly uri: string | null; } | null; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "ExtraUser"; }) | null; readonly " $refType": "TypenameInsideWithOverlappingFields"; }; @@ -2284,18 +2260,15 @@ fragment TypenameAliases on Actor { ~~~~~~~~~~ OUTPUT ~~~~~~~~~~ // TypenameInside.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameInside = { +export type TypenameInside = ({ readonly __typename: "User"; readonly firstName: string | null; - readonly " $refType": "TypenameInside"; } | { readonly __typename: "Page"; readonly username: string | null; - readonly " $refType": "TypenameInside"; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "ExtraUser"; +}) & { readonly " $refType": "TypenameInside"; }; export type TypenameInside$data = TypenameInside; @@ -2307,18 +2280,15 @@ export type TypenameInside$key = { // TypenameOutside.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameOutside = { +export type TypenameOutside = ({ readonly __typename: "User"; readonly firstName: string | null; - readonly " $refType": "TypenameOutside"; } | { readonly __typename: "Page"; readonly username: string | null; - readonly " $refType": "TypenameOutside"; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "ExtraUser"; +}) & { readonly " $refType": "TypenameOutside"; }; export type TypenameOutside$data = TypenameOutside; @@ -2330,15 +2300,21 @@ export type TypenameOutside$key = { // TypenameOutsideWithAbstractType.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameOutsideWithAbstractType = { - readonly __typename: string; +export type TypenameOutsideWithAbstractType = ({ + readonly __typename: "User"; + readonly firstName: string | null; + readonly address: { + readonly street: string | null; + readonly city: string | null; + } | null; +} | { + readonly __typename: "Comment" | "Feedback" | "Page" | "PhotoStory" | "Story"; +}) & { readonly username?: string | null; readonly address?: { readonly city: string | null; readonly country: string | null; - readonly street?: string | null; } | null; - readonly firstName?: string | null; readonly " $refType": "TypenameOutsideWithAbstractType"; }; export type TypenameOutsideWithAbstractType$data = TypenameOutsideWithAbstractType; @@ -2351,8 +2327,8 @@ export type TypenameOutsideWithAbstractType$key = { // TypenameWithoutSpreads.graphql import { FragmentRefs } from "relay-runtime"; export type TypenameWithoutSpreads = { - readonly firstName: string | null; readonly __typename: "User"; + readonly firstName: string | null; readonly " $refType": "TypenameWithoutSpreads"; }; export type TypenameWithoutSpreads$data = TypenameWithoutSpreads; @@ -2378,11 +2354,16 @@ export type TypenameWithoutSpreadsAbstractType$key = { // TypenameWithCommonSelections.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameWithCommonSelections = { - readonly __typename: string; +export type TypenameWithCommonSelections = ({ + readonly __typename: "User"; + readonly firstName: string | null; +} | { + readonly __typename: "Page"; + readonly username: string | null; +} | { + readonly __typename: "ExtraUser"; +}) & { readonly name: string | null; - readonly firstName?: string | null; - readonly username?: string | null; readonly " $refType": "TypenameWithCommonSelections"; }; export type TypenameWithCommonSelections$data = TypenameWithCommonSelections; @@ -2394,18 +2375,15 @@ export type TypenameWithCommonSelections$key = { // TypenameAlias.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameAlias = { +export type TypenameAlias = ({ readonly _typeAlias: "User"; readonly firstName: string | null; - readonly " $refType": "TypenameAlias"; } | { readonly _typeAlias: "Page"; readonly username: string | null; - readonly " $refType": "TypenameAlias"; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly _typeAlias: "%other"; + readonly _typeAlias: "ExtraUser"; +}) & { readonly " $refType": "TypenameAlias"; }; export type TypenameAlias$data = TypenameAlias; @@ -2417,23 +2395,18 @@ export type TypenameAlias$key = { // TypenameAliases.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameAliases = { +export type TypenameAliases = ({ readonly _typeAlias1: "User"; readonly _typeAlias2: "User"; readonly firstName: string | null; - readonly " $refType": "TypenameAliases"; } | { readonly _typeAlias1: "Page"; readonly _typeAlias2: "Page"; readonly username: string | null; - readonly " $refType": "TypenameAliases"; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly _typeAlias1: "%other"; - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly _typeAlias2: "%other"; + readonly _typeAlias1: "ExtraUser"; + readonly _typeAlias2: "ExtraUser"; +}) & { readonly " $refType": "TypenameAliases"; }; export type TypenameAliases$data = TypenameAliases; @@ -2658,9 +2631,7 @@ export type ConcreateTypes = { readonly __typename: "User"; readonly name: string | null; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "ExtraUser"; }) | null; readonly " $refType": "ConcreateTypes"; }; @@ -2676,11 +2647,6 @@ import { FragmentRefs } from "relay-runtime"; export type PictureFragment = { readonly __typename: "Image"; readonly " $refType": "PictureFragment"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "PictureFragment"; }; export type PictureFragment$data = PictureFragment; export type PictureFragment$key = { @@ -2707,11 +2673,6 @@ import { FragmentRefs } from "relay-runtime"; export type PageFragment = { readonly __typename: "Page"; readonly " $refType": "PageFragment"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "PageFragment"; }; export type PageFragment$data = PageFragment; export type PageFragment$key = { @@ -2725,11 +2686,6 @@ import { FragmentRefs } from "relay-runtime"; export type UserFrag1 = { readonly __typename: "User"; readonly " $refType": "UserFrag1"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "UserFrag1"; }; export type UserFrag1$data = UserFrag1; export type UserFrag1$key = { @@ -2743,11 +2699,6 @@ import { FragmentRefs } from "relay-runtime"; export type UserFrag2 = { readonly __typename: "User"; readonly " $refType": "UserFrag2"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "UserFrag2"; }; export type UserFrag2$data = UserFrag2; export type UserFrag2$key = { @@ -2903,11 +2854,6 @@ import { FragmentRefs } from "relay-runtime"; export type SomeFragment = { readonly __typename: "User"; readonly " $refType": "SomeFragment"; -} | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; - readonly " $refType": "SomeFragment"; }; export type SomeFragment$data = SomeFragment; export type SomeFragment$key = { @@ -2981,9 +2927,7 @@ export type UnionTypeTestResponse = { readonly __typename: "FakeNode"; readonly id: string; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "NonNode"; }) | null; }; export type UnionTypeTest = { @@ -4512,20 +4456,27 @@ export type RelayClientIDFieldQueryResponse = { readonly __typename: string; readonly id: string; } | null; - readonly node: { - readonly __id: string; - readonly __typename: string; - readonly id: string; - readonly commentBody?: { + readonly node: (({ + readonly __typename: "Comment"; + readonly commentBody: (({ + readonly __typename: "PlainCommentBody"; readonly __id: string; - readonly __typename: string; - readonly text?: { + readonly text: { readonly __id: string; readonly __typename: string; readonly text: string | null; } | null; - } | null; - } | null; + } | { + readonly __typename: "MarkdownCommentBody"; + }) & { + readonly __id: string; + }) | null; + } | { + readonly __typename: "Feedback" | "Page" | "PhotoStory" | "Story" | "User"; + }) & { + readonly __id: string; + readonly id: string; + }) | null; }; export type RelayClientIDFieldQuery = { readonly response: RelayClientIDFieldQueryResponse; @@ -4718,9 +4669,7 @@ export type TypenameInsideWithOverlappingFields = { readonly uri: string | null; } | null; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "ExtraUser"; }) | null; readonly " $refType": "TypenameInsideWithOverlappingFields"; }; @@ -4818,18 +4767,15 @@ fragment TypenameAliases on Actor { ~~~~~~~~~~ OUTPUT ~~~~~~~~~~ // TypenameInside.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameInside = { +export type TypenameInside = ({ readonly __typename: "User"; readonly firstName: string | null; - readonly " $refType": "TypenameInside"; } | { readonly __typename: "Page"; readonly username: string | null; - readonly " $refType": "TypenameInside"; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "ExtraUser"; +}) & { readonly " $refType": "TypenameInside"; }; export type TypenameInside$data = TypenameInside; @@ -4841,18 +4787,15 @@ export type TypenameInside$key = { // TypenameOutside.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameOutside = { +export type TypenameOutside = ({ readonly __typename: "User"; readonly firstName: string | null; - readonly " $refType": "TypenameOutside"; } | { readonly __typename: "Page"; readonly username: string | null; - readonly " $refType": "TypenameOutside"; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly __typename: "%other"; + readonly __typename: "ExtraUser"; +}) & { readonly " $refType": "TypenameOutside"; }; export type TypenameOutside$data = TypenameOutside; @@ -4864,15 +4807,21 @@ export type TypenameOutside$key = { // TypenameOutsideWithAbstractType.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameOutsideWithAbstractType = { - readonly __typename: string; +export type TypenameOutsideWithAbstractType = ({ + readonly __typename: "User"; + readonly firstName: string | null; + readonly address: { + readonly street: string | null; + readonly city: string | null; + } | null; +} | { + readonly __typename: "Comment" | "Feedback" | "Page" | "PhotoStory" | "Story"; +}) & { readonly username?: string | null; readonly address?: { readonly city: string | null; readonly country: string | null; - readonly street?: string | null; } | null; - readonly firstName?: string | null; readonly " $refType": "TypenameOutsideWithAbstractType"; }; export type TypenameOutsideWithAbstractType$data = TypenameOutsideWithAbstractType; @@ -4885,8 +4834,8 @@ export type TypenameOutsideWithAbstractType$key = { // TypenameWithoutSpreads.graphql import { FragmentRefs } from "relay-runtime"; export type TypenameWithoutSpreads = { - readonly firstName: string | null; readonly __typename: "User"; + readonly firstName: string | null; readonly " $refType": "TypenameWithoutSpreads"; }; export type TypenameWithoutSpreads$data = TypenameWithoutSpreads; @@ -4912,11 +4861,16 @@ export type TypenameWithoutSpreadsAbstractType$key = { // TypenameWithCommonSelections.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameWithCommonSelections = { - readonly __typename: string; +export type TypenameWithCommonSelections = ({ + readonly __typename: "User"; + readonly firstName: string | null; +} | { + readonly __typename: "Page"; + readonly username: string | null; +} | { + readonly __typename: "ExtraUser"; +}) & { readonly name: string | null; - readonly firstName?: string | null; - readonly username?: string | null; readonly " $refType": "TypenameWithCommonSelections"; }; export type TypenameWithCommonSelections$data = TypenameWithCommonSelections; @@ -4928,18 +4882,15 @@ export type TypenameWithCommonSelections$key = { // TypenameAlias.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameAlias = { +export type TypenameAlias = ({ readonly _typeAlias: "User"; readonly firstName: string | null; - readonly " $refType": "TypenameAlias"; } | { readonly _typeAlias: "Page"; readonly username: string | null; - readonly " $refType": "TypenameAlias"; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly _typeAlias: "%other"; + readonly _typeAlias: "ExtraUser"; +}) & { readonly " $refType": "TypenameAlias"; }; export type TypenameAlias$data = TypenameAlias; @@ -4951,23 +4902,18 @@ export type TypenameAlias$key = { // TypenameAliases.graphql import { FragmentRefs } from "relay-runtime"; -export type TypenameAliases = { +export type TypenameAliases = ({ readonly _typeAlias1: "User"; readonly _typeAlias2: "User"; readonly firstName: string | null; - readonly " $refType": "TypenameAliases"; } | { readonly _typeAlias1: "Page"; readonly _typeAlias2: "Page"; readonly username: string | null; - readonly " $refType": "TypenameAliases"; } | { - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly _typeAlias1: "%other"; - /*This will never be '%other', but we need some - value in case none of the concrete values match.*/ - readonly _typeAlias2: "%other"; + readonly _typeAlias1: "ExtraUser"; + readonly _typeAlias2: "ExtraUser"; +}) & { readonly " $refType": "TypenameAliases"; }; export type TypenameAliases$data = TypenameAliases;