GraphQL Code Generator plugin for generating ready-to-use TypedDocumentNode based on GraphQL operations
npx @tessl/cli install tessl/npm-graphql-codegen--typed-document-node@5.1.0GraphQL Code Generator plugin that generates ready-to-use TypedDocumentNode based on GraphQL operations. It creates strongly-typed TypeScript representations of GraphQL queries, mutations, and subscriptions that maintain type safety between GraphQL operations and TypeScript code, enabling better development experience with autocompletion, compile-time error checking, and refactoring support.
npm install @graphql-codegen/typed-document-nodegraphql (^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0)import { plugin, validate, TypeScriptTypedDocumentNodesConfig } from "@graphql-codegen/typed-document-node";For CommonJS:
const { plugin, validate, TypeScriptTypedDocumentNodesConfig } = require("@graphql-codegen/typed-document-node");This package is used as a plugin within the GraphQL Code Generator ecosystem:
# codegen.yml
schema: './schema.graphql'
documents: './src/**/*.graphql'
generates:
'./src/generated/graphql.ts':
plugins:
- 'typescript'
- 'typescript-operations'
- 'typed-document-node'
config:
flattenGeneratedTypes: false
addTypenameToSelectionSets: false// Usage of generated TypedDocumentNode
import { GetUserDocument } from './generated/graphql';
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
// The generated document is strongly typed
const userQuery: TypedDocumentNode<GetUserQuery, GetUserQueryVariables> = GetUserDocument;The plugin operates through several key components:
Main plugin function that generates TypedDocumentNode code from GraphQL operations.
/**
* Main plugin function for generating TypedDocumentNode code
* @param schema - The GraphQL schema
* @param rawDocuments - Array of GraphQL document files
* @param config - Plugin configuration options
* @returns Generated code output with prepend imports and content
*/
const plugin: PluginFunction<TypeScriptTypedDocumentNodesConfig>;Validates that the output file has the correct extension for TypeScript.
/**
* Validates plugin configuration and output file
* @param _schema - The GraphQL schema (unused)
* @param _documents - Array of document files (unused)
* @param _config - Plugin configuration (unused)
* @param outputFile - Path to the output file
* @throws Error if output file doesn't have .ts or .tsx extension
*/
const validate: PluginValidateFn<RawClientSideBasePluginConfig>;When using string document mode (documentMode: "string"), the plugin generates this class for string-based documents.
/**
* String-based typed document node class (generated when documentMode is "string")
*/
class TypedDocumentString<TResult, TVariables>
extends String
implements DocumentTypeDecoration<TResult, TVariables>
{
__apiType?: NonNullable<DocumentTypeDecoration<TResult, TVariables>['__apiType']>;
private value: string;
public __meta__?: Record<string, any> | undefined;
/**
* Creates a new typed document string
* @param value - The GraphQL document string
* @param __meta__ - Optional metadata
*/
constructor(value: string, __meta__?: Record<string, any> | undefined);
/**
* Returns the document string with type decoration
* @returns Typed document string
*/
override toString(): string & DocumentTypeDecoration<TResult, TVariables>;
}Configuration interface for the plugin.
/**
* Configuration options for the typed document node plugin
*/
interface TypeScriptTypedDocumentNodesConfig extends RawClientSideBasePluginConfig {
/**
* Flatten fragment spread and inline fragments into a simple selection set before generating
* @default false
*/
flattenGeneratedTypes?: boolean;
/**
* Add __typename to selection sets for better type safety
* @default false
*/
addTypenameToSelectionSets?: boolean;
}The plugin supports multiple document output modes inherited from the base plugin:
/**
* GraphQL schema representation
*/
type GraphQLSchema = import('graphql').GraphQLSchema;
/**
* Document file representation from GraphQL Code Generator
*/
interface DocumentFile {
location: string;
document: DocumentNode;
}
/**
* Loaded fragment representation
*/
interface LoadedFragment {
node: FragmentDefinitionNode;
name: string;
onType: string;
isExternal: boolean;
}
/**
* Plugin function type from GraphQL Code Generator
*/
type PluginFunction<T> = (
schema: GraphQLSchema,
documents: Types.DocumentFile[],
config: T
) => Types.ComplexPluginOutput | string;
/**
* Plugin validation function type
*/
type PluginValidateFn<T> = (
schema: GraphQLSchema,
documents: Types.DocumentFile[],
config: T,
outputFile: string
) => Promise<void>;
/**
* Base configuration interface from visitor plugin common
*/
interface RawClientSideBasePluginConfig {
// Configuration options from the base plugin
}
/**
* Plugin output with prepend imports and content
*/
interface ComplexPluginOutput {
prepend: string[];
content: string;
}/**
* Type decoration interface from @graphql-typed-document-node/core
*/
interface DocumentTypeDecoration<TResult, TVariables> {
__apiType?: {
result: TResult;
variables: TVariables;
};
}The plugin throws errors in the following scenarios:
.ts or .tsx extensionimport { useQuery } from '@apollo/client';
import { GetUserDocument, GetUserQuery, GetUserQueryVariables } from './generated/graphql';
function UserProfile({ userId }: { userId: string }) {
const { data, loading, error } = useQuery<GetUserQuery, GetUserQueryVariables>(
GetUserDocument,
{ variables: { id: userId } }
);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>User: {data?.user?.name}</div>;
}import { request } from 'graphql-request';
import { GetUserDocument, GetUserQuery, GetUserQueryVariables } from './generated/graphql';
async function getUser(userId: string): Promise<GetUserQuery> {
return request<GetUserQuery, GetUserQueryVariables>(
'https://api.example.com/graphql',
GetUserDocument,
{ id: userId }
);
}import { useQuery } from 'urql';
import { GetUserDocument } from './generated/graphql';
function UserProfile({ userId }: { userId: string }) {
const [result] = useQuery({
query: GetUserDocument,
variables: { id: userId }
});
const { data, fetching, error } = result;
if (fetching) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>User: {data?.user?.name}</div>;
}