Subchapter 1.13
references/typescript-codegen.mdMarkdown4 KBView on GitHub
This guide covers setting up GraphQL Code Generator for type-safe Apollo Client usage with TypeScript.
npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typed-document-nodeCreate a codegen.ts file in your project root:
// codegen.ts
import { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {
overwrite: true,
schema: "<URL_OF_YOUR_GRAPHQL_API>",
// This assumes that all your source files are in a top-level `src/` directory - you might need to adjust this to your file structure
documents: ["src/**/*.{ts,tsx}"],
// Don't exit with non-zero status when there are no documents
ignoreNoDocuments: true,
generates: {
// Use a path that works the best for the structure of your application
"./src/types/__generated__/graphql.ts": {
plugins: ["typescript", "typescript-operations", "typed-document-node"],
config: {
avoidOptionals: {
// Use `null` for nullable fields instead of optionals
field: true,
// Allow nullable input fields to remain unspecified
inputValue: false,
},
// Use `unknown` instead of `any` for unconfigured scalars
defaultScalarType: "unknown",
// Apollo Client always includes `__typename` fields
nonOptionalTypename: true,
// Apollo Client doesn't add the `__typename` field to root types so
// don't generate a type for the `__typename` for root operation types.
skipTypeNameForRoot: true,
},
},
},
};
export default config;To enable data masking with GraphQL Code Generator, create a type declaration file to inform Apollo Client about the generated types:
// apollo-client.d.ts
import { GraphQLCodegenDataMasking } from "@apollo/client/masking";
declare module "@apollo/client" {
export interface TypeOverrides
extends GraphQLCodegenDataMasking.TypeOverrides {}
}Add a script to your package.json:
{
"scripts": {
"codegen": "graphql-codegen"
}
}Run code generation:
npm run codegenThe typed-document-node plugin generates TypedDocumentNode types that Apollo Client hooks automatically infer.
Define your operations inline with the if (false) pattern. This allows GraphQL Code Generator to detect and extract operations without executing the code at runtime (bundlers omit this dead code during minification):
import { gql } from "@apollo/client";
// This query will never be consumed in runtime code, so it is wrapped in `if (false)` so the bundler can omit it when bundling.
if (false) {
gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
}After running npm run codegen, import the generated TypedDocumentNode:
import { useQuery } from "@apollo/client/react";
import { GetUserDocument } from "./queries.generated";
function UserProfile({ userId }: { userId: string }) {
// Types are automatically inferred from GetUserDocument
const { data } = useQuery(GetUserDocument, {
variables: { id: userId },
});
// ... other logic ...
return <div>{data?.user.name}</div>;
}TypedDocumentNode - never use manual generics like useQuery<QueryType, VariablesType>().