UNPKG

8.96 kBMarkdownView Raw
1# `graphql-typescript-definitions`
2
3> Generate TypeScript definition files from .graphql documents
4
5## Installation
6
7```
8npm install graphql-typescript-definitions --save-dev
9```
10
11or, with Yarn:
12
13```
14yarn add graphql-typescript-definitions --dev
15```
16
17## Usage
18
19This package will generate matching `.d.ts` files for each `.graphql` file you specify. It will generate types in the following format:
20
21* A default export for the type that will be generated by a GraphQL loader (GraphQL’s `DocumentNode` type, but augmented as `graphql-typed`’s `DocumentNode` which includes additional type details about the operation).
22
23* An interface for each query, mutation, and fragment, named `<OpertionName><Query | Mutation | Fragment>Data`. For example, `query Home {}` becomes `export interface HomeQueryData {}`.
24
25* A namespace for each operation that includes any nested types. Nested types are named in pascal case using their keypath from the root of the operation. For example, if we imagine the following GraphQL schema (using the [GraphQL IDL](https://www.graph.cool/docs/faq/graphql-idl-schema-definition-language-kr84dktnp0/)):
26
27 ```graphql
28 type Person {
29 name: String!
30 relatives: [Person!]!
31 }
32
33 type Query {
34 person: Person
35 }
36 ```
37
38 and the following query:
39
40 ```graphql
41 query Someone {
42 person {
43 name
44 relatives {
45 name
46 }
47 }
48 }
49 ```
50
51 The following exports would be generated:
52
53 ```typescript
54 export interface SomeoneQueryData {
55 person?: SomeoneQueryData.Person | null;
56 }
57
58 export namespace SomeoneQueryData {
59 export interface Person {
60 name: string;
61 relatives: SomeoneQueryData.PersonRelatives[];
62 }
63
64 export interface PersonRelatives {
65 name: string;
66 }
67 }
68 ```
69
70 This allows you to use the full query’s type, as well as any of the subtypes that make up that query type. This is particularly useful for list or nullable types, where you can directly the access the underlying type without any additional help from TypeScript:
71
72 ```typescript
73 import someoneQueryDocument, {SomeoneQueryData} from './Someone.graphql';
74
75 let data: SomeoneQueryData;
76 let person: SomeoneQueryData.Person;
77 ```
78
79### Operation
80
81On startup this tool performs the following actions:
82
83* Loads all schemas
84* Extracts all enums, input objects, and custom scalars as schema types
85* Writes the schema types to `types.ts` (or `${projectName}-types.ts` for named projects)
86 * Written in directory provided by `--schema-types-path` argument
87 * Override `--schema-types-path` per project with the `schemaTypesPath` extension
88
89### Configuration
90
91This tool reads schema information from a [`.graphqlconfig`](https://github.com/Shopify/graphql-tools-web/tree/master/packages/graphql-tool-utilities#configuration) file in the project root.
92
93#### Examples
94
95A project configuration with a `schemaTypesPath` override
96
97```json
98{
99 "schemaPath": "build/schema.json",
100 "includes": "app/**/*.graphql",
101 "extensions": {
102 "schemaTypesPath": "app/bar/types/graphql"
103 }
104}
105```
106
107### Type Generation
108
109#### Nullability
110
111As demonstrated in the root `person` field in the example above, nullable fields are represented as optional types, in a union with `null`. Nullable items in list fields (i.e., `[Person]!`) are represented as a union type with `null`.
112
113#### Interfaces and Unions
114
115Interface an union fields are represented as union types in cases where there are spreads that could result in different fields on different concrete types. The type names for these cases are named the same as the default naming (pascal case version of the keypath for the field), but with the type condition appended to the end. All cases not covered by fragments are extracted into a type with a postpended `Other` name.
116
117```graphql
118# Schema
119interface Named {
120 name: String!
121}
122
123type Person implements Named {
124 name: String!
125 occupation: String
126}
127
128type Dog implements Named {
129 name: String!
130 legs: Int!
131}
132
133type Cat implements Named {
134 name: String!
135 livesLeft: Int!
136}
137
138type Horse implements Named {
139 name: String!
140 topSpeed: Float!
141}
142
143type Query {
144 named: Named
145}
146```
147
148```graphql
149# Query
150query SomeNamed {
151 named {
152 name
153 ... on Person {
154 occupation
155 }
156 ... on Dog {
157 legs
158 }
159 }
160}
161```
162
163```typescript
164// generated types
165export interface SomeNamedData {
166 named?:
167 | SomeNamedData.NamedPerson
168 | SomeNamedData.NamedDog
169 | SomeNamedData.NamedOther
170 | null;
171}
172
173export namespace SomeNamedData {
174 export interface NamedPerson {
175 __typename: 'Person';
176 name: string;
177 occupation?: string | null;
178 }
179 export interface NamedDog {
180 __typename: 'Dog';
181 name: string;
182 legs: number;
183 }
184 export interface NamedOther {
185 __typename: 'Cat' | 'Horse';
186 name: string;
187 }
188}
189```
190
191Note that the above example assumes that you specify the `--add-typename` argument. These types are only useful when a typename is included either explicitly or with this argument, as otherwise there is no simple way for TypeScript to disambiguate the union type.
192
193#### Schema Types
194
195Input types (enums, input objects, and custom scalars) are generated once, in a central location, and imported within each typing file. You can use these definitions to reference the schema types in other application code as well; in particular, GraphQL enums are turned into corresponding TypeScript `enum`s. The schema types directory is specified using the `--schema-types-path` argument (detailed below), and the format for the generated enums can be specified using the `--enum-format` option.
196
197### CLI
198
199```sh
200graphql-typescript-definitions --schema-types-path app/types
201```
202
203As noted above, the configuration of your schema and GraphQL documents is done via a `.graphqlconfig` file, as this allows configuration to shared between tools. The CLI does support a few additional options, though:
204
205* `--schema-types-path`: specifies a directory to write schema types (**REQUIRED**)
206* `--watch`: watches the include globbing patterns for changes and re-processes files (default = `false`)
207* `--cwd`: run tool for `.graphqlconfig` located in this directory (default = `process.cwd()`)
208* `--add-typename`: adds a `__typename` field to every object type (default = `true`)
209* `--enum-format`: specifies output format for enum types (default = `undefined`)
210 * Options: `camel-case`, `pascal-case`, `snake-case`, `screaming-snake-case`
211 * `undefined` results in using the unchanged name from the schema (verbatim)
212* `--custom-scalars`: specifies custom types to use in place of scalar types in your GraphQL schema. See below for details.
213
214#### Examples
215
216```sh
217# run tool for .graphqlconfig in current directory, produces ./app/graphql/types
218graphql-typescript-definitions --schema-types-path app/graphql/types
219
220# run watcher for .graphqlconfig in current directory, produces ./app/graphql/types
221graphql-typescript-definitions --schema-types-path app/graphql/types --watch
222
223# run tool for .graphqlconfig in a child directory, produces ./src/app/graphql/types
224graphql-typescript-definitions --cwd src --schema-types-path app/graphql/types
225```
226
227#### `--custom-scalars`
228
229By default, all custom scalars are exported as an alias for `string`. You can export a different type for these scalars by passing in a `--custom-scalars` option. This option is a JSON-serialized object that specifies what custom type to import from a package and re-export as the type for that scalar. For example, assuming the following schema:
230
231```graphql
232scalar HtmlString
233```
234
235You may want a custom TypeScript type for any field of this GraphQL type (for example, to restrict functions to use only this type, and not any arbitrary string). Assuming you have an installed npm package by the name of `my-custom-type-package`, and this package exports a named `SafeString` type, you could pass the following `--custom-scalars` option:
236
237```sh
238yarn run graphql-typescript-definitions --schema-path 'build/schema.json' --schema-types-path 'src/schema' --custom-scalars '{"HtmlString": {"name": "SafeString", package: "my-custom-type-package"}}'
239```
240
241With this configuration, your custom scalar would be exported roughly as follows:
242
243```ts
244import {SafeString} from 'my-custom-type-package';
245export type HtmlString = SafeString;
246```
247
248### Node
249
250```js
251const {Builder} = require('graphql-typescript-definitions');
252
253const builder = new Builder({
254 schemaTypesPath: 'app/graphql/types',
255});
256
257builder.on('build', (build) => {
258 // See the source file for details on the shape of the object returned here
259 console.log(build);
260});
261
262builder.on('error', (error) => {
263 console.error(error);
264});
265
266// Optionally, you can pass {watch: true} here to re-run on changes
267builder.run();
268```
269
270As with the CLI, you can pass options to customize the build and behavior:
271
272* `watch`
273* `enumFormat` (use the exported `EnumFormat` enum)
274* `graphQLFiles`
275* `schemaPath`
276* `schemaTypesPath`
277* `customScalars`
278* `config` (custom `GraphQLConfig` instance)