npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ts-gql-plugin

v1.5.1

Published

TypeScript Language Service Plugin for GraphQL DocumentNode typing

Downloads

916

Readme

ts-gql-plugin

npm license CI - CD

A TypeScript Language Service Plugin adding GraphQL DocumentNode typing.


  • :triangular_ruler: Typed GraphQL operations
  • :x: No code generation
  • :toolbox: CLI support
  • :pencil: Editor support with autocomplete / quick-infos / "go to definition"
  • :link: Multi-projects support

Using gql from graphql-tag gives you generic DocumentNode type, which does not allow you to manipulate typed requested data when used with Apollo for example. To resolve that you can use code generators creating typescript code with correct types, but it adds lot of generated code with risk of obsolete code and bad development comfort.

ts-gql-plugin is meant to solve this issue, by replacing most of code generation by compiler-side typing, using TypeScript Language Service Plugin.

Get started

Install with your package manager

yarn add -D ts-gql-plugin
npm install -D ts-gql-plugin

Then add plugin to your tsconfig.json

{
  "compilerOptions": {
    "plugins": [
      {
        "name": "ts-gql-plugin"
      }
    ]
  }
}

Since this plugin uses graphql-config you should add a config file targeting your GraphQL schema.

// .graphqlrc
{
  "schema": "./schema.graphql"
}

Depending on how you want to use it:

To work this plugin requires a specific syntax:

gql(`...`);

A concrete example:

import { gql } from 'graphql-tag';

// TypedDocumentNode<{ user, users }, { id }>
gql(`
  query User1($id: ID!) {
    user(id: $id) {
      id
      name
  }
    users {
      id
    }
  }
`);

You can find more examples in example/.

Configuration

Configuration can be done at 2 levels: in tsconfig.json and in graphql-config file.

tsconfig.json

Checkout config type & default values in plugin-config.ts.

Log level 'debug' writes log files into ts-gql-plugin-logs directory. When running by VSCode this directory can be hard to find, checkout TSServer logs where files paths are logged. These logs contain updated code with hidden types generated by plugin.

graphql-config

You can add project-related configuration using extension "ts-gql".

// .graphqlrc
{
  "schema": "./schema.graphql",
  "extensions": {
    "ts-gql": {
      "codegenConfig": {
        "defaultScalarType": "unknown",
        "scalars": {
          "DateTime": "String"
        }
      }
    }
  }
}

Checkout config type in extension-config.ts.

Multi-projects configuration

If you should handle multiple GraphQL projects (= multiple schemas), define projects into your graphql-config file.

// .graphqlrc
{
  "projects": {
    "Catalog": {
      "schema": "./catalog/schema.graphql"
    },
    "Channel": {
      "schema": "./channel/schema.graphql"
    }
  }
}

graphql-config extensions should not be added in root level, but in each projects

Then into your plugin config define project name regex, following your own constraints. This regex is used to extract project name from operations.

{
  "compilerOptions": {
    "plugins": [
      {
        "name": "ts-gql-plugin",
        "projectNameRegex": "([A-Z][a-z]*)"
      }
    ]
  }
}

Finally, create your operations following regex constraints.

gql(`
  query CatalogProduct($id: ID!) {
    product(id: $id) {
      id
      name
    }
  }
`);

gql(`
  query ChannelItem($id: ID!) {
    item(id: $id) {
      id
      name
    }
  }
`);

With this kind of configuration, each of these operations match corresponding project, so its own schema.

Use of generated types

Even if this plugin allows you to avoid code generation, you may want to use generated types. For this kind of use a global module is exposed. Named TsGql, you can access from it every generated types.

gql(`
  query ProfileAuth {
    ...
  }
`);

const authInput: TsGql.ProfileAuthInput = {
  username,
  password,
};

To use TsGql in a file without gql uses, you should put a @ts-gql tag with the project name you want to use, anywhere in your file. This is the only way for ts-gql-plugin to know without performance impact when you want to access generated types.

// @ts-gql Profile

const authInput: TsGql.ProfileAuthInput = {
  username,
  password,
};

Enums

Since enums persist on runtime, they cannot be exposed by ts-gql-plugin. To solve this issue, types are generated instead of enums.

# schema-profile.graphql

enum OAuthProvider {
  GOOGLE
  FACEBOOK
}

So this enum can be used like that:

// @ts-gql Profile

const provider: TsGql.ProfileOAuthProvider = 'GOOGLE';

Also you may want to list every possible values from a GraphQL enum, like to be used with HTML <select> elements. To handle this case ts-gql-plugin exposes an utility type, UnionToArray, which allows to create a tuple from an union with a strong constraint forcing to give every possible values.

import { UnionToArray } from 'ts-gql-plugin';

const providerList: UnionToArray<TsGql.ProfileOAuthProvider> = [
  'GOOGLE',
  'FACEBOOK',
];

VSCode

You should set your workspace's version of TypeScript, which will load plugins from your tsconfig.json file.

# Open VSCode command palette with Shift + Ctrl/Cmd + P
> TypeScript: Select TypeScript version...

> Use Workspace Version

After a config change you may have to restart TS server.

> TypeScript: Restart TS server

TS server logs

You can see plugin logs openning TS server log

> TypeScript: Open TS server log

Then search for ts-gql-plugin occurences.

To see more logs consider passing logLevel to 'verbose' or 'debug' !

GraphQL extension

To have highlighting between other features, you can use GraphQL extension for VSCode.

Since this extension does not handle multi-projects configurations you may want to use GraphQL: Syntax Highlighting extension instead. This extension only gives syntax highlighting.

CLI

Because of Language Service design limitations tsc does not load plugins. So building or type-checking your files using CLI cannot use ts-gql-plugin.

As a workaround you can use tsc-ls, a compiler handling language service plugins.

Caveats & constraints

// not handled, waiting for TypeScript #33304
gql`
  query {...}
`;
  • since Language Service feature is limited concerning types overriding, solution was to parse & override text source files during TS server process, which is subobtimal for performances (best solution would have been to work with AST)
  • as described upper, CLI is not handled out-of-box because of tsc design limitations

Benchmark

You can see performance impact using ts-gql-plugin: https://chnapy.github.io/ts-gql-plugin/dev/bench

Keep in mind that this benchmark shows the "worst case": it's done using a tsconfig including only a single index.ts file with only gql operations, so plugin use is overrepresented.

Changelog

Checkout releases to see each version changes.

Contribute

Issues

Please fill issues with reproductible steps & relevant logs (check VSCode TS server logs).

Work on this project - get started

This project uses devcontainers and is made to work on it.

Run checkers

yarn c:type
yarn c:lint
yarn c:test

Build

yarn build