TypeScript Code Generation
This guide covers setting up GraphQL Code Generator for type-safe Apollo Client usage with TypeScript.
Installation
npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typed-document-nodeConfiguration
Create 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;Enable Data Masking
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 {}
}Running Code Generation
Add a script to your package.json:
{
"scripts": {
"codegen": "graphql-codegen"
}
}Run code generation:
npm run codegenUsage with Apollo Client
The typed-document-node plugin generates TypedDocumentNode types that Apollo Client hooks automatically infer.
Defining Operations
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
}
}
`;
}Using Generated Types
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>;
}Important Notes
- The typed-document-node plugin might have a bundle size tradeoff but can prevent inconsistencies and is best suited for usage with LLMs, so it is recommended for most applications.
- See the GraphQL Code Generator documentation for other recommended configuration patterns if required.
- Apollo Client hooks automatically infer types from
TypedDocumentNode- never use manual generics likeuseQuery<QueryType, VariablesType>().