diff --git a/src/type/__tests__/validation-test.ts b/src/type/__tests__/validation-test.ts index 3c2fe21500..ca07a220d6 100644 --- a/src/type/__tests__/validation-test.ts +++ b/src/type/__tests__/validation-test.ts @@ -747,7 +747,7 @@ describe('Type System: Union types must be valid', () => { ]); }); - it('rejects a Union type with non-Object members types', () => { + it('rejects a Union type with non-Object member types', () => { let schema = buildSchema(` type Query { test: BadUnion @@ -807,6 +807,47 @@ describe('Type System: Union types must be valid', () => { ]); } }); + + it('rejects a Union type with duplicate non-Object member types', () => { + let schema = buildSchema(` + type Query { + test: BadUnion + } + + type TypeA { + field: String + } + + union BadUnion = + | Int + | String + | TypeA + | Int + | String + `); + + schema = extendSchema(schema, parse('extend union BadUnion = Int')); + + expectJSON(validateSchema(schema)).toDeepEqual([ + { + message: + 'Union type BadUnion can only include Object types, it cannot include Int.', + locations: [ + { line: 11, column: 11 }, + { line: 14, column: 11 }, + { line: 1, column: 25 }, + ], + }, + { + message: + 'Union type BadUnion can only include Object types, it cannot include String.', + locations: [ + { line: 12, column: 11 }, + { line: 15, column: 11 }, + ], + }, + ]); + }); }); describe('Type System: Input Objects must have fields', () => { diff --git a/src/type/validate.ts b/src/type/validate.ts index 3a69a8c6eb..b4e1568beb 100644 --- a/src/type/validate.ts +++ b/src/type/validate.ts @@ -480,7 +480,20 @@ function validateUnionMembers( } const includedTypeNames = new Set(); + const includedInvalidTypes = new Set(); for (const memberType of memberTypes) { + if (!isObjectType(memberType)) { + const typeString = inspect(memberType); + if (!includedInvalidTypes.has(typeString)) { + context.reportError( + `Union type ${union.name} can only include Object types, ` + + `it cannot include ${inspect(memberType)}.`, + getUnionMemberTypeNodes(union, String(memberType)), + ); + includedInvalidTypes.add(typeString); + } + continue; + } if (includedTypeNames.has(memberType.name)) { context.reportError( `Union type ${union.name} can only include type ${memberType} once.`, @@ -489,13 +502,6 @@ function validateUnionMembers( continue; } includedTypeNames.add(memberType.name); - if (!isObjectType(memberType)) { - context.reportError( - `Union type ${union.name} can only include Object types, ` + - `it cannot include ${inspect(memberType)}.`, - getUnionMemberTypeNodes(union, String(memberType)), - ); - } } }