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.
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.
Currently only distributed as a Go module:
go get github.com/deref/extractgqlts
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
.
It should not require many, many files to define a single UI Component. GraphQL queries must appear in the one and only component file.
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.
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.
The assumption is that you will have one module directory that will contain three code files:
./types.generated.ts
- The generated output of theextractgqlts
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.
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.
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.