Skip to content

Commit

Permalink
[typescript-resolvers] Extract interface types into ResolversInterfac…
Browse files Browse the repository at this point in the history
…eTypes + add interface to resolversNonOptionalTypename + simplify ResolversUnionTypes (#9229)

* Extract Interface Types to separate type in TypeScript resolvers

* Make ResolversUnionTypes similar to ResolversInterfaceTypes
  • Loading branch information
eddeee888 committed Apr 27, 2023
1 parent 79abdf1 commit 5aa95aa
Show file tree
Hide file tree
Showing 9 changed files with 922 additions and 533 deletions.
8 changes: 8 additions & 0 deletions .changeset/long-pears-peel.md
@@ -0,0 +1,8 @@
---
'@graphql-codegen/visitor-plugin-common': minor
'@graphql-codegen/typescript-resolvers': minor
---

Use generic to simplify ResolversUnionTypes

This follows the `ResolversInterfaceTypes`'s approach where the `RefType` generic is used to refer back to `ResolversTypes` or `ResolversParentTypes` in cases of nested Union types
100 changes: 100 additions & 0 deletions .changeset/tricky-swans-happen.md
@@ -0,0 +1,100 @@
---
'@graphql-codegen/visitor-plugin-common': minor
'@graphql-codegen/typescript-resolvers': minor
---

Extract interfaces to ResolversInterfaceTypes and add to resolversNonOptionalTypename

1. `ResolversInterfaceTypes` is a new type that keeps track of a GraphQL interface and its implementing types.

For example, consider this schema:

```graphql
extend type Query {
character(id: ID!): CharacterNode
}

interface CharacterNode {
id: ID!
}

type Wizard implements CharacterNode {
id: ID!
screenName: String!
spells: [String!]!
}

type Fighter implements CharacterNode {
id: ID!
screenName: String!
powerLevel: Int!
}
```

The generated types will look like this:

```ts
export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = {
CharacterNode: Fighter | Wizard;
};

export type ResolversTypes = {
// other types...
CharacterNode: ResolverTypeWrapper<ResolversInterfaceTypes<ResolversTypes>["CharacterNode"]>;
Fighter: ResolverTypeWrapper<Fighter>;
Wizard: ResolverTypeWrapper<Wizard>;
// other types...
};

export type ResolversParentTypes = {
// other types...
CharacterNode: ResolversInterfaceTypes<ResolversParentTypes>["CharacterNode"];
Fighter: Fighter;
Wizard: Wizard;
// other types...
};
```

The `RefType` generic is used to reference back to `ResolversTypes` and `ResolversParentTypes` in some cases such as field returning a Union.

2. `resolversNonOptionalTypename` also affects `ResolversInterfaceTypes`

Using the schema above, if we use `resolversNonOptionalTypename` option:

```typescript
const config: CodegenConfig = {
schema: 'src/schema/**/*.graphql',
generates: {
'src/schema/types.ts': {
plugins: ['typescript', 'typescript-resolvers'],
config: {
resolversNonOptionalTypename: true // Or `resolversNonOptionalTypename: { interfaceImplementingType: true }`
}
},
},
};
```

Then, the generated type looks like this:

```ts
export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = {
CharacterNode: (Fighter & { __typename: "Fighter" }) | (Wizard & { __typename: "Wizard" });
};

export type ResolversTypes = {
// other types...
CharacterNode: ResolverTypeWrapper<ResolversInterfaceTypes<ResolversTypes>["CharacterNode"]>;
Fighter: ResolverTypeWrapper<Fighter>;
Wizard: ResolverTypeWrapper<Wizard>;
// other types...
};

export type ResolversParentTypes = {
// other types...
CharacterNode: ResolversInterfaceTypes<ResolversParentTypes>["CharacterNode"];
Fighter: Fighter;
Wizard: Wizard;
// other types...
};
```
11 changes: 3 additions & 8 deletions dev-test/modules/types.ts
Expand Up @@ -163,12 +163,7 @@ export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs
) => TResult | Promise<TResult>;

/** Mapping of union types */
export type ResolversUnionTypes = {
PaymentOption: CreditCard | Paypal;
};

/** Mapping of union parent types */
export type ResolversUnionParentTypes = {
export type ResolversUnionTypes<RefType extends Record<string, unknown>> = {
PaymentOption: CreditCard | Paypal;
};

Expand All @@ -183,7 +178,7 @@ export type ResolversTypes = {
ID: ResolverTypeWrapper<Scalars['ID']>;
Int: ResolverTypeWrapper<Scalars['Int']>;
Mutation: ResolverTypeWrapper<{}>;
PaymentOption: ResolverTypeWrapper<ResolversUnionTypes['PaymentOption']>;
PaymentOption: ResolverTypeWrapper<ResolversUnionTypes<ResolversTypes>['PaymentOption']>;
Paypal: ResolverTypeWrapper<Paypal>;
Query: ResolverTypeWrapper<{}>;
String: ResolverTypeWrapper<Scalars['String']>;
Expand All @@ -203,7 +198,7 @@ export type ResolversParentTypes = {
ID: Scalars['ID'];
Int: Scalars['Int'];
Mutation: {};
PaymentOption: ResolversUnionParentTypes['PaymentOption'];
PaymentOption: ResolversUnionTypes<ResolversParentTypes>['PaymentOption'];
Paypal: Paypal;
Query: {};
String: Scalars['String'];
Expand Down

0 comments on commit 5aa95aa

Please sign in to comment.