Skip to content

deref/extractgqlts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

extractgqlts - Extract GraphQL TypeScript

Generates TypeScript types from GraphQL usage in string literals.

This code generation tool is intended to be extremely fast to execute. Additionally, strong conventions make it uncomplicated to use.

Status

STABILIZING

You are likely to encounter small problems using this. However, it being used successfully by an in-development product now, so it does indeed work.

Feedback and/or contributions welcome.

Install

Currently only distributed as a Go module:

go get github.com/deref/extractgqlts

Usage

Write queries in your code using string literals with the following prefix: `#graphql. For example:

const { query } = './example/graphql';

const profileFragment = `#graphql
  fragment Profile on Named {
    name
  }
`

const query(`#graphql
  {
    node(id: $id) {
      id
      ...Profile
    }
  }
`, {
  include: [profileFragment],
});

Run the code generator, something like this:

extractgqlts \
  --schema ./src/graphql/schema.gql \
  './src/components/{tsx,svelte}' \
  > ./src/graphql/types.generated.ts

The generated output contains a mapped type called QueryTypes. This maps query strings to { data, variables } structures for use in whatever driver functions you supply yourself. For a simple example:

import { QueryTypes } from './types.generated.ts';

const query = <TQuery extends keyof QueryTypes>(
  query: TQuery,
  variables: QueryTypes[TQuery]['variables'],
): Promise<QueryTypes[TQuery]['data']> => {
  // ...
}

A more complete example can be found in this gist extracted from a Svelte project.

If you have custom scalars, you'll also need ./src/graphql/scalars.ts.

Design Constraints & Implementation Notes

Queries Live in Component Files

It should not require many, many files to define a single UI Component. GraphQL queries must appear in the one and only component file.

No Manual Type Imports

Given a global schema, the query string itself should be sufficient to determine the data and variable types. You shouldn't need to give the query an explicit name and then laborously import a type based on that name. Until TypeScript offers type providers, the only way to do this without a manual import is to use a mapped type keyed by the query string.

Framework Agnostic

Does not assume React, Apollo, or anything else.

This means you must provide your own entrypoint to the generated types that indexes the QueryTypes map.

Convention Over Configuration

The assumption is that you will have one module directory that will contain three code files:

  • ./types.generated.ts - The generated output of the extractgqlts tool. Note, this name is not (yet?) enforced.
  • ./scalars.ts - Exports scalar types to be imported by ./types.generated.ts.
  • ./index.ts - Consumes the generated types and exports exposes your framework-specific entrypoints.

Global Names

Assumes there is one global namespace of query and fragment names in your application. If you violate this, you'll get a TypeScript error regarding a duplicate identifier.

No TypeScript Parsing

Extracts GraphQL documents from TypeScript files by scanning for `#graphql. This character sequence starts a JavaScript string literal that is assumed to contain a GraphQL document. This pattern is also recognized by common IDE plugins, such as the most popular one for VS Code.

Note, we look for a string literal and not a gql` template literal tag because of a TypeScript limitation.

About

Extracts TypeScript types from GraphQL string literals

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published