• Stars
    star
    163
  • Rank 229,810 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 4 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Write GraphQL queries with a gql tag in TypeScript -> have generated types

ts-gql

Write GraphQL queries with a gql tag in TypeScript -> have generated types

Why?

There are lots of great tools(some of which ts-gql uses internally!) for generating TypeScript types from GraphQL queries though a lot of the solutions have at least one of two problems:

  • The writing of a query isn't connected to the type that it results in
  • You're forced to write queries in .graphql files rather than inline
    • This also often means that you can't use fragments or that there's a new import syntax to learn

How does ts-gql solve these problems?

When using ts-gql, you write GraphQL queries with a tagged template literal like normal.

import { gql } from "@ts-gql/tag";

let myQuery = gql`
  query MyQuery {
    hello
  }
`;

And then our ESLint plugin will auto-fix it to

import { gql } from "@ts-gql/tag";

let myQuery = gql`
  query MyQuery {
    hello
  }
` as import("../__generated__/ts-gql/MyQuery.ts").type;

You'll have the best experience if you have ESLint auto fix on save enabled in your editor.

Why do we need to add `as import("__generated__/ts-gql/MyQuery.ts").type`?

TypeScript doesn't currently type tagged template literals with literal string types so there is no way to get the correct type based on the call so we have to add as import("__generated__/ts-gql/MyQuery.ts").type though there are issues discussing it which would remove the need for this.

You can then use GraphQL Clients like Apollo Client, urql or any other GraphQL client that supports @graphql-typed-document-node/core and get types for the variables and data.

Getting Started

When using ts-gql, you'll need @ts-gql/tag, @ts-gql/eslint-plugin and @ts-gql/compiler.

npm install graphql @ts-gql/tag @ts-gql/eslint-plugin @ts-gql/compiler

If you're not already using ESLint and @typescript-eslint/parser, you'll need those too.

You'll need to add the ESLint plugin to your config and enable the @ts-gql/ts-gql rule. Your config might look something like this:

{
  "parser": "@typescript-eslint/parser",
  "plugins": ["@ts-gql"],
  "rules": {
    "@ts-gql/ts-gql": "error"
  }
}

You now need to tell ts-gql where your GraphQL SDL file or introspection query result is. To do this, add to your package.json. Replace schema.graphql with the path to your SDL or introspection query result.

{
  "ts-gql": {
    "schema": "schema.graphql"
  }
}

Add a script to your package.json and run it. You should run this in postinstall so that the types are generated when install happens.

{
  "scripts": {
    "postinstall": "ts-gql build",
    "ts-gql:build": "ts-gql build",
    "ts-gql:watch": "ts-gql watch"
  }
}

You can run npm run ts-gql:build to do a single build or npm run ts-gql:watch to start watching.

If you're using Next.js, you can use @ts-gql/next to automatically start ts-gql's watcher when you start Next.js's dev server.

Using Apollo

See docs/using-ts-gql-with-apollo.md for how to use ts-gql with Apollo.

FAQ

Why not let people interpolate fragments so you don't have to have unique fragment/operation names?

This was the original plan! It's been abandoned though for a couple reasons:

  • Build time performance
    • Requiring type checking before you can generate types makes things much slower
      • This is compounded by the fact that you not only have to do type checking but you have to do type checking n times where n is the maximum fragment depth. Because we want to encourage the use of fragments, a tool that gets significantly slower as you use more fragments would make it impractical to use fragments
  • Having to either not have Prettier work for documents with fragment interpolations(because Prettier will not format interpolations in GraphQL documents unless they are outside of the content of the document so you couldn't interpolate a fragment where it's used) or still have to name it and then you'd still have the potential for name conflicts(unless you added a syntax for renaming fragments at which point, I would say that that's way more complexity without a substantial gain)
  • Not allowing interpolation makes it very very clear what you can and can't do. Even if we allowed interpolations, they would be constrained which is a very difficult thing to explain.
  • Apollo already doesn't allow non-unique names anyway for their tooling anyway
  • TODO: there are more reasons

How do you pass types around?

@ts-gql/tag comes with an OperationData type to get the type of an operation(mutation or query) and FragmentData to get the type for a fragment.

import { gql, OperationData, FragmentData } from "@ts-gql/tag";

let myQuery = gql`
  query MyQuery {
    hello
  }
` as import("../__generated__/ts-gql/MyQuery.ts").type;

type MyQueryType = OperationData<typeof myQuery>;

let myFragment = gql`
  query MyFragment_something on SomeType {
    hello
  }
` as import("../__generated__/ts-gql/MyFragment_something.ts").type;

type MyFragmentType = FragmentData<typeof myFragment>;

This seems a lot like Relay, why not just use Relay?

You're right! There are a lot of similarities between Relay and ts-gql. There are some important differences though. Relay is an entire GraphQL client, it can do a lot of cool things because of that but that also means that if you want the things that the Relay compiler offers, you have to use Relay which may not appeal to everyone. If Relay does work well for you though, that's fine too, use it!

ts-gql isn't trying to be a GraphQL client, it's only trying to provide a way to type GraphQL queries so that clients can .

Non-Goals

  • Improve the experience of creating GraphQL APIs

Thanks

More Repositories

1

keystatic

First class CMS experience, TypeScript API, Markdown & YAML/JSON based, no DB
TypeScript
1,110
star
2

react-markings

**Markdown** in <Components/>, <Components/> in **Markdown**
JavaScript
882
star
3

manypkg

☔️ An umbrella for your monorepo
TypeScript
882
star
4

react-conf-app

React Conf 2017 Companion App - built with React Native
JavaScript
798
star
5

monorepo

📦 Thinkmill's Monorepo Style Guide
JavaScript
189
star
6

reacteu-app

ReactEurope TouchstoneJS Mobile App
Java
161
star
7

monorepo-starter

An example setup of how to do a monorepo, used in our monorepo 'getting started' guide
JavaScript
129
star
8

react-testing

Examples of how to test React.js applications
106
star
9

hyperterm-spacegray

Spacegray theme for hyperterm
JavaScript
81
star
10

emery

💎 Polish for the rough parts of TypeScript
TypeScript
81
star
11

magical-types

🔮 Document React components and other stuff typed with TypeScript magically
TypeScript
77
star
12

jest-expect-contain-deep

Assert deeply nested values in Jest
JavaScript
67
star
13

reacteu-api

ReactEurope KeystoneJS API Server
JavaScript
54
star
14

jest-fixtures

Use file system fixtures in Jest
JavaScript
39
star
15

design-system

🎨 Thinkmill's Design System Style Guide
31
star
16

graphql

🍇 Thinkmill's GraphQL Style Guide
31
star
17

reacteu-assets

24
star
18

changelogs-xyz

A place to see changelogs for any npm package
JavaScript
24
star
19

meetup-alternative

A free, open source, self-hosted alternative to meetup.com
JavaScript
18
star
20

graphql-ts

Type-safety for constructing GraphQL schemas in TypeScript
TypeScript
18
star
21

code-challenge

Monthly code challenges
JavaScript
17
star
22

magical-forms

TypeScript
14
star
23

keystone-forgotten-password

Keystone Password Reset Plugin for Keystone 4.0
JavaScript
13
star
24

markings

📝
TypeScript
12
star
25

keystatic-demo-landing-page

TypeScript
12
star
26

sydjs-keystatic

TypeScript
10
star
27

elemental-ui

TypeScript
10
star
28

pragmatic-forms

A pragmatic approach to forms in React
JavaScript
10
star
29

untitled-docs

📚
TypeScript
9
star
30

manylicense

A node_modules license reporting tool for monorepos that use yarn workspaces.
JavaScript
8
star
31

keystatic-demo-blog

TypeScript
8
star
32

keystatic-examples-knowledge-base

Roff
8
star
33

docsmill

TypeScript
7
star
34

react-conf-app-assets

Assets for the React Conf App
7
star
35

pyn

Rust
5
star
36

parse-toml-stream

Parse TOML files in streams chunked by [sections]
JavaScript
5
star
37

sweet-changelogs

What it says on the tin
JavaScript
4
star
38

keystatic-astro-test

TypeScript
4
star
39

built-with-keystatic

A website showcasing projects built with Keystatic.
Astro
3
star
40

auto-approve-action

A GitHub action to automatically approve(and dismiss approval) of PRs based on a condition
TypeScript
3
star
41

keystone-experiments

JavaScript
3
star
42

node-worker

🎡 A simple, promise-based, worker framework.
JavaScript
3
star
43

badge

"Supported by Thinkmill" badge for READMEs
2
star
44

ui-performance

Testing ui performance
JavaScript
2
star
45

shed

🚲 Find all your bike shedding needs under one roof
JavaScript
2
star
46

changesets-publish-slack-action

TypeScript
2
star
47

barista-slack-integration

Slack integration to make coffee orders easy!
CSS
2
star
48

keystatic-manual-setup-demo

TypeScript
1
star
49

keystatic-starter-portfolio

TypeScript
1
star
50

keystatic-starter-docs-nextjs

TypeScript
1
star
51

keystatic-template-astro

Astro
1
star
52

eslint-config-thinkmill

Thinkmill standard code style config
1
star
53

pingpong-champion

A scoring app
JavaScript
1
star
54

heroku-buildpack-bolt

Shell
1
star
55

sftp-stream-test

Tests whether the response from an SFTP server is the same as the one from downloading a file directly with the request library.
JavaScript
1
star