diff --git a/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts index a37350bf7a6..33748e1f94b 100644 --- a/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts @@ -491,6 +491,31 @@ export interface RawTypesConfig extends RawConfig { * ``` */ directiveArgumentAndInputFieldMappingTypeSuffix?: string; + /** + * @description When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself. + * @default false + * + * @exampleMarkdown + * ## Override all definition types + * + * ```ts filename="codegen.ts" + * import type { CodegenConfig } from '@graphql-codegen/cli' + * + * const config: CodegenConfig = { + * // ... + * generates: { + * 'path/to/file.ts': { + * plugins: ['typescript'], + * config: { + * useImplementingTypes: true + * } + * } + * } + * } + * export default config + * ``` + */ + useImplementingTypes?: boolean; } const onlyUnderscoresPattern = /^_+$/; @@ -788,7 +813,7 @@ export class BaseTypesVisitor< getInterfaceTypeDeclarationBlock( node: InterfaceTypeDefinitionNode, - _originalNode: InterfaceTypeDefinitionNode + originalNode: InterfaceTypeDefinitionNode ): DeclarationBlock { const declarationBlock = new DeclarationBlock(this._declarationBlockConfig) .export() @@ -796,6 +821,11 @@ export class BaseTypesVisitor< .withName(this.convertName(node)) .withComment(node.description?.value); + if (!this._parsedConfig.useImplementingTypes) { + const interfacesNames = originalNode.interfaces ? originalNode.interfaces.map(i => this.convertName(i)) : []; + declarationBlock.withContent(this.mergeInterfaces(interfacesNames, node.fields.length > 0)); + } + return declarationBlock.withBlock(node.fields.join('\n')); } diff --git a/packages/plugins/other/visitor-plugin-common/src/base-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/base-visitor.ts index 45903d52576..d3ebb885218 100644 --- a/packages/plugins/other/visitor-plugin-common/src/base-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/base-visitor.ts @@ -40,6 +40,7 @@ export interface ParsedConfig { importExtension: '' | `.${string}`; printFieldsOnNewLines: boolean; includeExternalFragments: boolean; + useImplementingTypes: boolean; } export interface RawConfig { diff --git a/packages/plugins/typescript/typescript/src/config.ts b/packages/plugins/typescript/typescript/src/config.ts index b9aed7cf961..d44ba83531b 100644 --- a/packages/plugins/typescript/typescript/src/config.ts +++ b/packages/plugins/typescript/typescript/src/config.ts @@ -411,31 +411,6 @@ export interface TypeScriptPluginConfig extends RawTypesConfig { * ``` */ disableDescriptions?: boolean; - /** - * @description When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself. - * @default false - * - * @exampleMarkdown - * ## Override all definition types - * - * ```ts filename="codegen.ts" - * import type { CodegenConfig } from '@graphql-codegen/cli' - * - * const config: CodegenConfig = { - * // ... - * generates: { - * 'path/to/file.ts': { - * plugins: ['typescript'], - * config: { - * useImplementingTypes: true - * } - * } - * } - * } - * export default config - * ``` - */ - useImplementingTypes?: boolean; /** * @name wrapEntireFieldDefinitions * @type boolean diff --git a/packages/plugins/typescript/typescript/tests/typescript.spec.ts b/packages/plugins/typescript/typescript/tests/typescript.spec.ts index f829c5e2550..5c641ab88f9 100644 --- a/packages/plugins/typescript/typescript/tests/typescript.spec.ts +++ b/packages/plugins/typescript/typescript/tests/typescript.spec.ts @@ -3950,6 +3950,31 @@ describe('TypeScript', () => { `); }); + it('should list parent interface on an intermediate interface - issue #10515', async () => { + const testSchema = buildSchema(/* GraphQL */ ` + interface TopLevel { + topLevelField: Boolean + } + + interface MidLevel implements TopLevel { + topLevelField: Boolean + midLevelField: Int + } + + type BottomLevel implements MidLevel & TopLevel { + topLevelField: Boolean + midLevelField: Int + bottomLevelField: String + } + `); + + const output = (await plugin(testSchema, [], {} as any, { outputFile: 'graphql.ts' })) as Types.ComplexPluginOutput; + + expect(output.content).toBeSimilarStringTo(` + type MidLevel = TopLevel & { + `); + }); + it('should use implementing types as node type - issue #5126', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Matrix {