# How To Generate TypeScript Types From GraphQL

Posted on September 30th, 2022 by Antonello Zanini

Using types in your applications makes your code more secure, consistent, and robust. Types also allow you to detect and avoid mistakes as early as possible in the development process. This is particularly true for GraphQL types, which play a key role in your frontend application and enable you to avoid unexpected bugs and errors.

Writing types manually is time-consuming, cumbersome, and error-prone. Luckily, you can use a **code generator to automatically generate TypeScript types from GraphQL queries**.  
Here, you will learn why adopting GraphQL types is so important, how to use graphql-codegen to generate TypeScript types from your .graphql files, why nullable fields may represent a problem, and how you can tackle this. 

## Why You Should Generate GraphQL Typescript Types

By default, [GraphQL validates all requests](https://graphql.org/learn/validation/) and returns only schema-valid responses. However, your frontend application may not know what a schema-valid response looks like. This is especially true when using untyped languages, such as JavaScript. In this case, you might accidentally access nonexistent properties or forget to implement the right checks on null. This could lead to several errors in the application.

By using a typed language and adopting GraphQL types, you can avoid all this. To define types, you should use a GraphQL code generator. This is because it enables you to automatically generate the required TypeScript types from your GraphQL queries. Specifically, GraphQL code generators generate input and output types for GraphQL requests in your code. This means that by generating GraphQL TypeScript types, you can **achieve extra validation for your GraphQL API calls**. Also, **accessing and using the results** of your GraphQL requests will become **easier and safer**.

## Generating Typescript Types From GraphQL With graphql-codegen

Let’s now learn how to automatically generate TypeScript types from your GraphQL queries with graphql-codegen.

Here, you will see an example based on a demo application that uses Next.js as the frontend technology and DatoCMS as the backend technology. Keep in mind that any TypeScript frontend technology and GraphQL-based backend technology will do.

Clone the [GitHub repository supporting the article](https://github.com/datocms/typescript-type-generation-graphql-example) and run the demo application with the following commands:

Terminal window

```bash
git clone https://github.com/datocms/typescript-type-generation-graphql-example
cd typescript-type-generation-graphql-example
npm i
npm run dev
```

Now, follow this step-by-step tutorial and learn how to generate TypeScript GraphQL types with graphql-codegen.

## Prerequisites

If you are a DatoCMS user, initialize a new project and create an Article model as follows:

(Image content)

First, you will need the following libraries:

-   [graphql](https://www.npmjs.com/package/graphql) \>\= 16.6.0
    
-   [graphql-request](https://www.npmjs.com/package/graphql-request) \>\= 5.0.0
    

You can install them with:

Terminal window

```bash
npm i graphql graphql-request
```

  
[graphql-request](https://github.com/prisma-labs/graphql-request) is a lightweight and minimal library developed Prisma Labs that provides exactly what you need to perform GraphQL requests. Note that any other GraphQL client, such as [Apollo GraphQL](https://www.npmjs.com/package/apollo-graphql), will do.

Then, you will need the following libraries to make the code generation work:

-   [@graphql-codegen/cli](https://www.npmjs.com/package/@graphql-codegen/cli) \>\= 2.12.0
    
-   [@graphql-codegen/typed-document-node](https://www.npmjs.com/package/@graphql-codegen/typed-document-node) \>\= 2.3.3
    
-   [@graphql-codegen/typescript](https://www.npmjs.com/package/@graphql-codegen/typescript) \>\= 2.7.3
    
-   [@graphql-codegen/typescript-operations](https://www.npmjs.com/package/@graphql-codegen/typescript-operations) \>\= 2.5.3
    
-   [@graphql-typed-document-node/core](https://www.npmjs.com/package/@graphql-typed-document-node/core) \>\= 3.1.1
    

  
You can add all these libraries to your project’s dependencies with the following npm command:

Terminal window

```bash
npm i @graphql-codegen/cli @graphql-codegen/typed-document-node @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-typed-document-node/core
```

  
@graphql-typed-document-node/core is required to implement the TypedDocumentNode approach. Learn more [here](https://the-guild.dev/blog/typed-document-node). 

The first four libraries belong to the [GraphQL codegen project](https://www.graphql-cli.com/codegen/). If you are not familiar with this project, **GraphQL codegen gives you the ability to generate code from your GraphQL schema and operations**.   
This is all you need to generate TypeScript types from your GraphQL queries.

Let’s now see how to do it! 

## Setting Up graphql-codegen

To make graphql-codegen work, you need to define a [GraphQL configuration file](https://the-guild.dev/blog/graphql-config).

Create `graphql.config.yml` file in the root directory of your project and initialize it as follows:

```yaml
schema:
  - https://graphql.datocms.com:
      headers:
        Authorization: "Bearer <YOUR_DATOCMS_API_TOKEN>"
documents: './graphql/**/*.graphql'
generates:
  graphql/generated.ts:
    plugins:
      - typescript
      - typescript-operations
      - typed-document-node
    config:
      strictScalars: true
      scalars:
        BooleanType: boolean
        CustomData: Record<string, unknown>
        Date: string
        DateTime: string
        FloatType: number
        IntType: number
        ItemId: string
        JsonField: unknown
        MetaTagAttributes: Record<string, string>
        UploadId: string

      # Optional, gives meta fields a leading underscore
      namingConvention:
        # enumValues: './pascalCaseWithUnderscores'
```

Note that the documents field must contain the path to the `.graphql` files storing your GraphQL queries. Also, change the schema field with the URL to your GraphQL schema. In this case, the GraphQL schema is retrieved directly from DatoCMS. Learn more on [how to use GraphQL with DatoCMS](https://www.datocms.com/blog/graphql-and-datocms.md).

If you are wondering what the scalars mentioned in the `graphql.config.yml` file are, take a look at [this](https://www.datocms.com/docs/content-delivery-api/custom-scalar-types.md).

In a nutshell, DatoCMS uses some custom [GraphQL scalar types](https://graphql.org/learn/schema/#scalar-types). Therefore, you need to define them in your config file in order for the code generator to be able to transform the results retrieved from the [DatoCMS Content Delivery API](https://www.datocms.com/docs/content-delivery-api.md) into TypeScript types.

Keep also in mind that the `graphql.config.yml` file can be used in the [GraphQL extension](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql) for Visual Studio Code to get auto-completion and error checking directly in the IDE on GraphQL queries.

You are now ready to generate TypeScript types with `graphql-codegen`.

### Optional: Leading underscores for meta fields

Optionally, you can use create the file `./pascalCaseWithUnderscores.js` to give your generated enums for meta fields a leading underscore, like `_CreatedAtAsc` instead of `CreatedAtAsc`. That file should look like this:

```javascript
/*
This the optional file /pascalCaseWithUnderscores.js

If you add this file to `namingConvention.enumValues` in your
`graphql.config.yml` file, it will add leading underscores where appropriate
*/

const { pascalCase } = require("change-case-all")

function pascalCaseWithUnderscores(str) {
  const result = pascalCase(str)

  if (!result) {
    return str
  }

  // if there is a leading underscore but it's not in the converted string, add it
  if (str.indexOf("_") === 0 && result.substring(0, 1) !== "_") {
    return `_${result}`
  }
  return result
}

module.exports = pascalCaseWithUnderscores
```

## Generating TypeScript Types With graphql-codegen

First, add the following line to the scripts section of your `package.json` file:

```json
"generate-ts-types": "graphql-codegen --config graphql.config.yml",
```

This will launch the graphql-codegen type generation command as defined in the `graphql.config.yml` configuration file defined above. You can learn more about the arguments supported by this command [here](https://www.graphql-cli.com/codegen/#usage).

Now, launch the command below:

Terminal window

```bash
npm run generate-ts-types
```

  
Wait for the code generation process to end, and you should get:

Terminal window

```bash
✔ Parse Configuration
✔ Generate outputs
```

Now, enter the `./graphql` directory, and you should be able to see a new `generated.ts` file. This contains all the TypeScript types generated by graphql-codegen.

In this simple DatoCMS example with only the Article model, `generated.ts` will look like as below:

```javascript
import { TypedDocumentNode as DocumentNode } from "@graphql-typed-document-node/core"
export type Maybe<T> = T | null
export type InputMaybe<T> = Maybe<T>
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] }
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> }
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> }
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
  ID: string
  String: string
  Boolean: boolean
  Int: number
  Float: number
  BooleanType: boolean
  CustomData: Record<string, unknown>
  DateTime: string
  FloatType: number
  IntType: number
  ItemId: string
  JsonField: unknown
  MetaTagAttributes: Record<string, string>
  UploadId: string
}

export type ArticleModelContentField = {
  __typename?: "ArticleModelContentField"
  blocks: Array<Scalars["String"]>
  links: Array<Scalars["String"]>
  value: Scalars["JsonField"]
}

export type ArticleModelFilter = {
  AND?: InputMaybe<Array<InputMaybe<ArticleModelFilter>>>
  OR?: InputMaybe<Array<InputMaybe<ArticleModelFilter>>>
  _createdAt?: InputMaybe<CreatedAtFilter>
  _firstPublishedAt?: InputMaybe<PublishedAtFilter>
  _isValid?: InputMaybe<BooleanFilter>
  _publicationScheduledAt?: InputMaybe<PublishedAtFilter>
  _publishedAt?: InputMaybe<PublishedAtFilter>
  _status?: InputMaybe<StatusFilter>
  _unpublishingScheduledAt?: InputMaybe<PublishedAtFilter>
  _updatedAt?: InputMaybe<UpdatedAtFilter>
  content?: InputMaybe<StructuredTextFilter>
  id?: InputMaybe<ItemIdFilter>
  image?: InputMaybe<FileFilter>
  slug?: InputMaybe<SlugFilter>
  title?: InputMaybe<StringFilter>
}

// Truncated for brevity...
```

You can have a look at the entire file [here](https://github.com/Tonel/typescript-type-generation-graphql-example/blob/main/graphql/generated.ts).

Now, let’s learn how to use these TypeScript types to perform GraphQL queries. 

## How To Use GraphQL API With Generated TypeScript Types

First, define a `request.ts` file in your lib folder as follows:

```javascript
import { request as graphqlRequest, Variables } from "graphql-request"
import { RequestDocument } from "graphql-request/dist/types"
import { TypedDocumentNode } from "@graphql-typed-document-node/core"

export function request<TDocument = any>(
  document: RequestDocument | TypedDocumentNode<TDocument, Variables>,
  variables?: Variables,
) {
  return graphqlRequest<TDocument, Variables>("https://graphql.datocms.com/", document, variables, {
    Authorization: "xxx",
  })
}
```

Here, the `graphql-request` client library is used to define a `request()` function. This performs GraphQL requests based on [the](https://the-guild.dev/blog/typed-document-node#2020-new-typeddocumentnode) [TypedDocumentNode](https://the-guild.dev/blog/typed-document-node#2020-new-typeddocumentnode) [approach](https://the-guild.dev/blog/typed-document-node#2020-new-typeddocumentnode) and returns typed results.

Let’s now see `request()` in action:

```javascript
import { GetStaticProps, NextPage } from "next"
import { Image as DatoImage } from "react-datocms"
import { HomeDocument, HomeQuery } from "../graphql/generated"
import { request } from "../lib/request"

const Home: NextPage<Props> = ({ result }) => {
  return (
    <ul>
      {result.allArticles.map((article) => (
        <li key={article.id}>
          {article.title} {article.image?.responsiveImage && <DatoImage data={article.image.responsiveImage} />}
        </li>
      ))}
    </ul>
  )
}

type Props = { result: HomeQuery }

export const getStaticProps: GetStaticProps<Props> = async (context) => {
  // retrieving the list of all articles
  const result = await request(HomeDocument)

  return {
    props: { result },
  }
}

export default Home
```

As you can see, you can **perform a GraphQL request simply by using the TypeScript auto-generated types and objects**. All you have to do is pass the right `TypedDocumentNode` to `request()` and it will return the expected typed result. 

In detail, note that the result object returned by `request()` contains the `allArticles` field storing the list of Article objects retrieved by the GraphQL query defined in the `./graphql/home.graphql` file below:

```graphql
query Home {
  allArticles {
    id
    title
    _createdAt
    _publishedAt
    image {
      ...responsiveImage
    }
  }
}

fragment responsiveImage on FileFieldInterface {
  responsiveImage(imgixParams: { w: 100, h: 100, fit: crop }) {
    alt
    aspectRatio
    base64
    bgColor
    height
    sizes
    src
    srcSet
    title
    webpSrcSet
    width
  }
}
```

If you are wondering what `HomeDocument` and `HomeQuery` look like, you can find their definition in your `generated.ts` file.

Also, note that the Home component uses the DatoCMS Next.js Image component. Learn more about what DatoCMS has to offer when it comes to [handling images in Next.js](https://www.datocms.com/docs/next-js/managing-images.md).

Congrats! You just learned how to automatically generate TypeScript types and objects from your GraphQL queries and use them to effortlessly perform GraphQL requests!

# Why Required Fields Are Nullable When Using a Headless CMS

Headless CMS solutions usually allow you to [define data models](https://www.datocms.com/docs/content-modelling.md) and populate entities accordingly. A data model is composed of several fields, each of which **can be marked as required.** When a field is considered required, it should always have a value. However, read carefully the following example and consider having a look at [this](https://community.datocms.com/t/make-required-fields-non-nullable-in-graphql-schema/1873) thread.

Let’s suppose you have an Article model defined as seen earlier. You have already created several article records, and you want to extend the Article model with a new subtitle required field.

(Image content)

DatoCMS field

Now, every time you create an article record, you will have to specify a subtitle. On the other hand, the subtitle field will be initialized as null on already existing records, despite the required validation. 

Therefore, any required field may actually have a null value. For this reason, all required fields are nullable in the GraphQL schema. Keep in mind that this is not a DatoCMS behavior, but an approach followed by all major headless CMS solutions.

Consequently, when automatically generating the TypeScript types from your GraphQL schema, **all required fields will be marked as nullable**. 

```javascript
export type ArticleRecord = RecordInterface & {
  __typename?: 'ArticleRecord';
  _createdAt: Scalars['DateTime'];
  /** Editing URL */
  _editingUrl?: Maybe<Scalars['String']>;
  _firstPublishedAt?: Maybe<Scalars['DateTime']>;
  _isValid: Scalars['BooleanType'];
  _modelApiKey: Scalars['String'];
  _publicationScheduledAt?: Maybe<Scalars['DateTime']>;
  _publishedAt?: Maybe<Scalars['DateTime']>;
  /** Generates SEO and Social card meta tags to be used in your frontend */
  _seoMetaTags: Array<Tag>;
  _status: ItemStatus;
  _unpublishingScheduledAt?: Maybe<Scalars['DateTime']>;
  _updatedAt: Scalars['DateTime'];
  content?: Maybe<ArticleModelContentField>;
  id: Scalars['ItemId'];
  image?: Maybe<FileField>;
  slug?: Maybe<Scalars['String']>;
  subtitle?: Maybe<Scalars['String']>;
  title?: Maybe<Scalars['String']>;
};
```

This is the auto-generated ArticleRecord TypeScript type. Notice that slug, subtitle, and title are all nullable, even if they are all marked as required.

This means that you always have to use the [optional chaining operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining), even if subtitle is required.

```javascript
// subtitle may be null despite the required validation
article.subtitle?.toUpperCase()
```

Keep in mind that you have to use the optional chaining operator or define null checks on subtitle on all record entities, even though it may not be null on any record.

Note that DatoCMS would also mark article records with a null value for required fields as invalid through a false value on the `is_valid` attribute. 

Filling your code with potentially unnecessary null checks is not elegant and makes your code dirtier, harder to read and maintain.

Fortunately, DatoCMS has a solution!

# How To Avoid Nullable Types on Required Field in DatoCMS

DatoCMS allows you to globally exclude invalid records without [always specifying an](https://www.datocms.com/docs/content-delivery-api/filtering-records.md#_is_valid) [`_isValid`](https://www.datocms.com/docs/content-delivery-api/filtering-records.md#_is_valid) [filter](https://www.datocms.com/docs/content-delivery-api/filtering-records.md#_is_valid) in your queries. You can achieve this by setting the following header:

```http
X-Exclude-Invalid: true
```

This enables the so-called [strict-mode for non-nullable GraphQL types](https://www.datocms.com/docs/content-delivery-api/api-endpoints.md#strict-mode-for-non-nullable-graphql-types). In detail, when this mode is enabled, a**ny field marked as required will be associated with a non-nullable GraphQL typ**e. Learn more about the [DatoCMS Strict Mode for GraphQL](https://www.datocms.com/blog/introducing-strict-mode-for-graphql-cda-get-the-best-typescript-dx.md).

Now, let’s see how to use this special header.

Update your graphql.config.yml file as follows:

```json
schema:
  - https://graphql.datocms.com:
      headers:
        Authorization: "<YOUR_DATOCMS_API_TOKEN>"
        X-Exclude-Invalid: true

# omitted for brevity...
```

  
And your `request.ts` file as below:

```javascript
import { request as graphqlRequest, Variables } from "graphql-request"
import { RequestDocument } from "graphql-request/dist/types"
import { TypedDocumentNode } from "@graphql-typed-document-node/core"

export function request<TDocument = any, TVariables = Record<string, any>>(
  document: RequestDocument | TypedDocumentNode<TDocument, Variables>,
  variables?: Variables,
) {
  return graphqlRequest<TDocument, Variables>("https://graphql.datocms.com/", document, variables, {
    Authorization: "<YOUR_DATOCMS_API_TOKEN>",
    "X-Exclude-Invalid": "true",
  })
}
```

  
Now, relaunch the code generation command:

Terminal window

```bash
npm run generate-ts-types
```

  
And `generated.ts` will contain the following type:

```javascript
export type ArticleRecord = RecordInterface & {
  __typename?: "ArticleRecord"
  _createdAt: Scalars["DateTime"]
  /** Editing URL */
  _editingUrl?: Maybe<Scalars["String"]>
  _firstPublishedAt?: Maybe<Scalars["DateTime"]>
  _isValid: Scalars["BooleanType"]
  _modelApiKey: Scalars["String"]
  _publicationScheduledAt?: Maybe<Scalars["DateTime"]>
  _publishedAt?: Maybe<Scalars["DateTime"]>
  /** Generates SEO and Social card meta tags to be used in your frontend */
  _seoMetaTags: Array<Tag>
  _status: ItemStatus
  _unpublishingScheduledAt?: Maybe<Scalars["DateTime"]>
  _updatedAt: Scalars["DateTime"]
  content: ArticleModelContentField
  id: Scalars["ItemId"]
  image?: Maybe<FileField>
  slug: Scalars["String"]
  subtitle: Scalars["String"]
  title: Scalars["String"]
}
```

Now, `slug`, `subtitle`, and `title` in the `ArticleRecord` type are non-nullable as expected. 

Et voilà! You no longer have to use unnecessary null checks in your TypeScript codebase.

# Conclusion

In this article, you learned why you need GraphQL TypeScript types and how to automatically generate them from your GraphQL queries. This can be easily achieved with a GraphQL code generator. In detail,  here you learned how to generate TypeScript types from GraphQL with `graphql-codegen`.

However, keep in mind that code generation comes with some challenges. This is particularly true when the GraphQL schema is defined through a headless CMS. In fact, required fields are generally marked as null.

Here, you learned how you can avoid this with DatoCMS, the powerful, fully-featured, easy-to-use headless CMS for developers and marketers.

Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on [Twitter](https://twitter.com/datocms) with any questions, comments, or suggestions.