-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[typescript-resolvers] Extract interface types into ResolversInterfac…
…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
Showing
9 changed files
with
922 additions
and
533 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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... | ||
}; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.