Skip to content

Commit 60baee9

Browse files
fix(visitor-plugin-common): add parent interfaces to interface type
Much like an `ObjectTypeDefinition`, an `InterfaceTypeDefinition` can also have parent interface types. With this change, the output reflects that.
1 parent bec7e74 commit 60baee9

File tree

4 files changed

+57
-26
lines changed

4 files changed

+57
-26
lines changed

packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,31 @@ export interface RawTypesConfig extends RawConfig {
491491
* ```
492492
*/
493493
directiveArgumentAndInputFieldMappingTypeSuffix?: string;
494+
/**
495+
* @description When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself.
496+
* @default false
497+
*
498+
* @exampleMarkdown
499+
* ## Override all definition types
500+
*
501+
* ```ts filename="codegen.ts"
502+
* import type { CodegenConfig } from '@graphql-codegen/cli'
503+
*
504+
* const config: CodegenConfig = {
505+
* // ...
506+
* generates: {
507+
* 'path/to/file.ts': {
508+
* plugins: ['typescript'],
509+
* config: {
510+
* useImplementingTypes: true
511+
* }
512+
* }
513+
* }
514+
* }
515+
* export default config
516+
* ```
517+
*/
518+
useImplementingTypes?: boolean;
494519
}
495520

496521
const onlyUnderscoresPattern = /^_+$/;
@@ -788,14 +813,19 @@ export class BaseTypesVisitor<
788813

789814
getInterfaceTypeDeclarationBlock(
790815
node: InterfaceTypeDefinitionNode,
791-
_originalNode: InterfaceTypeDefinitionNode
816+
originalNode: InterfaceTypeDefinitionNode
792817
): DeclarationBlock {
793818
const declarationBlock = new DeclarationBlock(this._declarationBlockConfig)
794819
.export()
795820
.asKind(this._parsedConfig.declarationKind.interface)
796821
.withName(this.convertName(node))
797822
.withComment(node.description?.value);
798823

824+
if (!this._parsedConfig.useImplementingTypes) {
825+
const interfacesNames = originalNode.interfaces ? originalNode.interfaces.map(i => this.convertName(i)) : [];
826+
declarationBlock.withContent(this.mergeInterfaces(interfacesNames, node.fields.length > 0));
827+
}
828+
799829
return declarationBlock.withBlock(node.fields.join('\n'));
800830
}
801831

packages/plugins/other/visitor-plugin-common/src/base-visitor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export interface ParsedConfig {
4040
importExtension: '' | `.${string}`;
4141
printFieldsOnNewLines: boolean;
4242
includeExternalFragments: boolean;
43+
useImplementingTypes: boolean;
4344
}
4445

4546
export interface RawConfig {

packages/plugins/typescript/typescript/src/config.ts

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -411,31 +411,6 @@ export interface TypeScriptPluginConfig extends RawTypesConfig {
411411
* ```
412412
*/
413413
disableDescriptions?: boolean;
414-
/**
415-
* @description When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself.
416-
* @default false
417-
*
418-
* @exampleMarkdown
419-
* ## Override all definition types
420-
*
421-
* ```ts filename="codegen.ts"
422-
* import type { CodegenConfig } from '@graphql-codegen/cli'
423-
*
424-
* const config: CodegenConfig = {
425-
* // ...
426-
* generates: {
427-
* 'path/to/file.ts': {
428-
* plugins: ['typescript'],
429-
* config: {
430-
* useImplementingTypes: true
431-
* }
432-
* }
433-
* }
434-
* }
435-
* export default config
436-
* ```
437-
*/
438-
useImplementingTypes?: boolean;
439414
/**
440415
* @name wrapEntireFieldDefinitions
441416
* @type boolean

packages/plugins/typescript/typescript/tests/typescript.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3950,6 +3950,31 @@ describe('TypeScript', () => {
39503950
`);
39513951
});
39523952

3953+
it('should list parent interface on an intermediate interface - issue #10515', async () => {
3954+
const testSchema = buildSchema(/* GraphQL */ `
3955+
interface TopLevel {
3956+
topLevelField: Boolean
3957+
}
3958+
3959+
interface MidLevel implements TopLevel {
3960+
topLevelField: Boolean
3961+
midLevelField: Int
3962+
}
3963+
3964+
type BottomLevel implements MidLevel & TopLevel {
3965+
topLevelField: Boolean
3966+
midLevelField: Int
3967+
bottomLevelField: String
3968+
}
3969+
`);
3970+
3971+
const output = (await plugin(testSchema, [], {} as any, { outputFile: 'graphql.ts' })) as Types.ComplexPluginOutput;
3972+
3973+
expect(output.content).toBeSimilarStringTo(`
3974+
type MidLevel = TopLevel & {
3975+
`);
3976+
});
3977+
39533978
it('should use implementing types as node type - issue #5126', async () => {
39543979
const testSchema = buildSchema(/* GraphQL */ `
39553980
type Matrix {

0 commit comments

Comments
 (0)