Skip to content

Commit c8ef37a

Browse files
noahsegerNoah Segercharlypoly
authored
fix(typescript-resolvers): Fix optional resolver types (#7004)
* Failing test * Organize better * Fix it * Revert mistaken test * Failing test * Organize better * Revert mistaken test * Revert Maybe change * Add new resolvers AvoidOptionasConfig key * Create fluffy-pumpkins-build.md Co-authored-by: Noah Seger <noah.seger@youearnedit.com> Co-authored-by: Charly POLY <1252066+charlypoly@users.noreply.github.com>
1 parent ca1a643 commit c8ef37a

File tree

6 files changed

+52
-4
lines changed

6 files changed

+52
-4
lines changed

‎.changeset/fluffy-pumpkins-build.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@graphql-codegen/typescript-resolvers": patch
3+
"@graphql-codegen/visitor-plugin-common": patch
4+
---
5+
6+
fix(typescript-resolvers): Fix optional field types

‎packages/plugins/other/visitor-plugin-common/src/avoid-optionals.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const DEFAULT_AVOID_OPTIONALS: AvoidOptionalsConfig = {
55
inputValue: false,
66
field: false,
77
defaultValue: false,
8+
resolvers: false,
89
};
910

1011
export function normalizeAvoidOptionals(avoidOptionals?: boolean | AvoidOptionalsConfig): AvoidOptionalsConfig {
@@ -14,6 +15,7 @@ export function normalizeAvoidOptionals(avoidOptionals?: boolean | AvoidOptional
1415
inputValue: avoidOptionals,
1516
field: avoidOptionals,
1617
defaultValue: avoidOptionals,
18+
resolvers: avoidOptionals,
1719
};
1820
}
1921

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,14 +987,15 @@ export class BaseResolversVisitor<
987987

988988
const resolverType = isSubscriptionType ? 'SubscriptionResolver' : directiveMappings[0] ?? 'Resolver';
989989

990+
const avoidOptionals = this.config.avoidOptionals?.resolvers ?? this.config.avoidOptionals === true;
990991
const signature: {
991992
name: string;
992993
modifier: string;
993994
type: string;
994995
genericTypes: string[];
995996
} = {
996997
name: node.name as any,
997-
modifier: this.config.avoidOptionals ? '' : '?',
998+
modifier: avoidOptionals ? '' : '?',
998999
type: resolverType,
9991000
genericTypes: [
10001001
mappedTypeKey,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export interface AvoidOptionalsConfig {
9595
object?: boolean;
9696
inputValue?: boolean;
9797
defaultValue?: boolean;
98+
resolvers?: boolean;
9899
}
99100

100101
export interface ParsedImport {

‎packages/plugins/typescript/resolvers/src/visitor.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,8 @@ export class TypeScriptResolversVisitor extends BaseResolversVisitor<
7474
}
7575

7676
protected formatRootResolver(schemaTypeName: string, resolverType: string, declarationKind: DeclarationKind): string {
77-
return `${schemaTypeName}${this.config.avoidOptionals ? '' : '?'}: ${resolverType}${this.getPunctuation(
78-
declarationKind
79-
)}`;
77+
const avoidOptionals = this.config.avoidOptionals?.resolvers ?? this.config.avoidOptionals === true;
78+
return `${schemaTypeName}${avoidOptionals ? '' : '?'}: ${resolverType}${this.getPunctuation(declarationKind)}`;
8079
}
8180

8281
private clearOptional(str: string): string {

‎packages/plugins/typescript/resolvers/tests/ts-resolvers.spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,4 +2290,43 @@ export type ResolverFn<TResult, TParent, TContext, TArgs> = (
22902290

22912291
await validate(result);
22922292
});
2293+
2294+
it('#7005 - avoidOptionals should preserve optional resolvers', async () => {
2295+
const testSchema = buildSchema(/* GraphQL */ `
2296+
type Query {
2297+
users(filter: UserFilterInput = {}): [User!]!
2298+
ping: String!
2299+
}
2300+
2301+
input UserFilterInput {
2302+
status: String = "ACTIVE"
2303+
}
2304+
2305+
type User {
2306+
id: ID!
2307+
}
2308+
`);
2309+
2310+
const output = (await plugin(
2311+
testSchema,
2312+
[],
2313+
{
2314+
avoidOptionals: {
2315+
defaultValue: true,
2316+
field: true,
2317+
inputValue: true,
2318+
object: true,
2319+
resolvers: false,
2320+
},
2321+
} as any,
2322+
{ outputFile: 'graphql.ts' }
2323+
)) as Types.ComplexPluginOutput;
2324+
2325+
expect(output.content).toBeSimilarStringTo(`
2326+
export type QueryResolvers<ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = {
2327+
users?: Resolver<Array<ResolversTypes['User']>, ParentType, ContextType, RequireFields<QueryUsersArgs, 'filter'>>;
2328+
ping?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
2329+
};
2330+
`);
2331+
});
22932332
});

0 commit comments

Comments
 (0)