From c290dd5bf77a0f07e06dcfd9a5f56700219216d7 Mon Sep 17 00:00:00 2001 From: Emma Hamilton Date: Mon, 23 Mar 2026 16:16:05 +1000 Subject: [PATCH 1/4] Allow `graphql@17` in peer dependencies --- packages/extend/package.json | 2 +- packages/schema/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/extend/package.json b/packages/extend/package.json index 1f40d40..aa6133f 100644 --- a/packages/extend/package.json +++ b/packages/extend/package.json @@ -18,7 +18,7 @@ "license": "MIT", "peerDependencies": { "@graphql-ts/schema": "^1.0.0", - "graphql": "16" + "graphql": "16 || 17" }, "devDependencies": { "@graphql-ts/schema": "workspace:^", diff --git a/packages/schema/package.json b/packages/schema/package.json index e8c1194..6b682e2 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -17,7 +17,7 @@ ], "license": "MIT", "peerDependencies": { - "graphql": "16" + "graphql": "16 || 17" }, "devDependencies": { "graphql": "^16.3.0" From 387a58a1a5e282b8a981f0376dcca52d17e46f2b Mon Sep 17 00:00:00 2001 From: Emma Hamilton Date: Fri, 17 Jul 2026 10:24:40 +1000 Subject: [PATCH 2/4] Update graphql in dev deps --- examples/basic-graphql-yoga/package.json | 2 +- examples/drizzle-graphql-yoga/package.json | 2 +- packages/extend/package.json | 2 +- packages/schema/package.json | 2 +- pnpm-lock.yaml | 90 +++++++++++----------- site/package.json | 2 +- test-project/package.json | 2 +- 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/examples/basic-graphql-yoga/package.json b/examples/basic-graphql-yoga/package.json index dd37c61..20080b1 100644 --- a/examples/basic-graphql-yoga/package.json +++ b/examples/basic-graphql-yoga/package.json @@ -4,7 +4,7 @@ "type": "module", "dependencies": { "@graphql-ts/schema": "^1.0.2", - "graphql": "^16.3.0", + "graphql": "^17.0.2", "graphql-yoga": "^5.22.0" }, "devDependencies": { diff --git a/examples/drizzle-graphql-yoga/package.json b/examples/drizzle-graphql-yoga/package.json index d8a5cea..fbc0480 100644 --- a/examples/drizzle-graphql-yoga/package.json +++ b/examples/drizzle-graphql-yoga/package.json @@ -5,7 +5,7 @@ "dependencies": { "@graphql-ts/schema": "^1.0.2", "drizzle-orm": "^1.0.0-rc.4", - "graphql": "^16.3.0", + "graphql": "^17.0.2", "graphql-yoga": "^5.22.0" }, "devDependencies": { diff --git a/packages/extend/package.json b/packages/extend/package.json index aa6133f..0cdb280 100644 --- a/packages/extend/package.json +++ b/packages/extend/package.json @@ -22,7 +22,7 @@ }, "devDependencies": { "@graphql-ts/schema": "workspace:^", - "graphql": "^16.3.0" + "graphql": "^17.0.2" }, "repository": "https://github.com/Thinkmill/graphql-ts/tree/main/packages/extend" } diff --git a/packages/schema/package.json b/packages/schema/package.json index 6b682e2..751ee8e 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -20,7 +20,7 @@ "graphql": "16 || 17" }, "devDependencies": { - "graphql": "^16.3.0" + "graphql": "^17.0.2" }, "repository": "https://github.com/Thinkmill/graphql-ts/tree/main/packages/schema" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3e29f54..2adecde 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,11 +58,11 @@ importers: specifier: ^1.0.2 version: link:../../packages/schema graphql: - specifier: ^16.3.0 - version: 16.10.0 + specifier: ^17.0.2 + version: 17.0.2 graphql-yoga: specifier: ^5.22.0 - version: 5.22.0(graphql@16.10.0) + version: 5.22.0(graphql@17.0.2) devDependencies: '@types/node': specifier: ^22.13.10 @@ -80,11 +80,11 @@ importers: specifier: ^1.0.0-rc.4 version: 1.0.0-rc.5-ab785fc(zod@4.4.3) graphql: - specifier: ^16.3.0 - version: 16.10.0 + specifier: ^17.0.2 + version: 17.0.2 graphql-yoga: specifier: ^5.22.0 - version: 5.22.0(graphql@16.10.0) + version: 5.22.0(graphql@17.0.2) devDependencies: '@types/node': specifier: ^22.13.10 @@ -102,14 +102,14 @@ importers: specifier: workspace:^ version: link:../schema graphql: - specifier: ^16.3.0 - version: 16.10.0 + specifier: ^17.0.2 + version: 17.0.2 packages/schema: devDependencies: graphql: - specifier: ^16.3.0 - version: 16.10.0 + specifier: ^17.0.2 + version: 17.0.2 site: dependencies: @@ -150,8 +150,8 @@ importers: specifier: ^0.4.0 version: 0.4.0(@expressive-code/core@0.44.1)(expressive-code@0.44.1)(typescript@6.0.3) graphql: - specifier: ^16.3.0 - version: 16.10.0 + specifier: ^17.0.2 + version: 17.0.2 mdast-util-mdx-jsx: specifier: ^3.2.0 version: 3.2.0 @@ -177,8 +177,8 @@ importers: specifier: ^22.13.10 version: 22.13.10 graphql: - specifier: ^16.3.0 - version: 16.10.0 + specifier: ^17.0.2 + version: 17.0.2 packages: @@ -3417,9 +3417,9 @@ packages: peerDependencies: graphql: ^15.2.0 || ^16.0.0 || ^17.0.0 - graphql@16.10.0: - resolution: {integrity: sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + graphql@17.0.2: + resolution: {integrity: sha512-FRWbddMxfkjiB7z+aQDWIR+E34xo9I8c9mtK2RPv8PmMzKRvrdsreHL/Ui/TmwHJfhHChEtsFPyMHKI+xuarQQ==} + engines: {node: ^22.0.0 || ^24.0.0 || ^25.0.0 || >=26.0.0} h3@1.15.11: resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} @@ -6366,57 +6366,57 @@ snapshots: '@fastify/busboy@3.2.2': {} - '@graphql-tools/executor@2.0.0(graphql@16.10.0)': + '@graphql-tools/executor@2.0.0(graphql@17.0.2)': dependencies: - '@graphql-tools/utils': 12.0.0(graphql@16.10.0) - '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) + '@graphql-tools/utils': 12.0.0(graphql@17.0.2) + '@graphql-typed-document-node/core': 3.2.0(graphql@17.0.2) '@repeaterjs/repeater': 3.1.0 '@whatwg-node/disposablestack': 0.0.6 '@whatwg-node/promise-helpers': 1.2.4 - graphql: 16.10.0 + graphql: 17.0.2 tslib: 2.8.1 - '@graphql-tools/merge@9.0.22(graphql@16.10.0)': + '@graphql-tools/merge@9.0.22(graphql@17.0.2)': dependencies: - '@graphql-tools/utils': 10.8.4(graphql@16.10.0) - graphql: 16.10.0 + '@graphql-tools/utils': 10.8.4(graphql@17.0.2) + graphql: 17.0.2 tslib: 2.8.1 - '@graphql-tools/schema@10.0.21(graphql@16.10.0)': + '@graphql-tools/schema@10.0.21(graphql@17.0.2)': dependencies: - '@graphql-tools/merge': 9.0.22(graphql@16.10.0) - '@graphql-tools/utils': 10.8.4(graphql@16.10.0) - graphql: 16.10.0 + '@graphql-tools/merge': 9.0.22(graphql@17.0.2) + '@graphql-tools/utils': 10.8.4(graphql@17.0.2) + graphql: 17.0.2 tslib: 2.8.1 - '@graphql-tools/utils@10.8.4(graphql@16.10.0)': + '@graphql-tools/utils@10.8.4(graphql@17.0.2)': dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) + '@graphql-typed-document-node/core': 3.2.0(graphql@17.0.2) '@whatwg-node/promise-helpers': 1.2.4 cross-inspect: 1.0.1 dset: 3.1.4 - graphql: 16.10.0 + graphql: 17.0.2 tslib: 2.8.1 - '@graphql-tools/utils@11.2.2(graphql@16.10.0)': + '@graphql-tools/utils@11.2.2(graphql@17.0.2)': dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) + '@graphql-typed-document-node/core': 3.2.0(graphql@17.0.2) '@whatwg-node/promise-helpers': 1.2.4 cross-inspect: 1.0.1 - graphql: 16.10.0 + graphql: 17.0.2 tslib: 2.8.1 - '@graphql-tools/utils@12.0.0(graphql@16.10.0)': + '@graphql-tools/utils@12.0.0(graphql@17.0.2)': dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) + '@graphql-typed-document-node/core': 3.2.0(graphql@17.0.2) '@whatwg-node/promise-helpers': 1.2.4 cross-inspect: 1.0.1 - graphql: 16.10.0 + graphql: 17.0.2 tslib: 2.8.1 - '@graphql-typed-document-node/core@3.2.0(graphql@16.10.0)': + '@graphql-typed-document-node/core@3.2.0(graphql@17.0.2)': dependencies: - graphql: 16.10.0 + graphql: 17.0.2 '@graphql-yoga/logger@2.0.1': dependencies: @@ -8013,23 +8013,23 @@ snapshots: graceful-fs@4.2.11: {} - graphql-yoga@5.22.0(graphql@16.10.0): + graphql-yoga@5.22.0(graphql@17.0.2): dependencies: '@envelop/core': 5.6.0 '@envelop/instrumentation': 1.0.0 - '@graphql-tools/executor': 2.0.0(graphql@16.10.0) - '@graphql-tools/schema': 10.0.21(graphql@16.10.0) - '@graphql-tools/utils': 11.2.2(graphql@16.10.0) + '@graphql-tools/executor': 2.0.0(graphql@17.0.2) + '@graphql-tools/schema': 10.0.21(graphql@17.0.2) + '@graphql-tools/utils': 11.2.2(graphql@17.0.2) '@graphql-yoga/logger': 2.0.1 '@graphql-yoga/subscription': 5.0.5 '@whatwg-node/fetch': 0.10.13 '@whatwg-node/promise-helpers': 1.3.2 '@whatwg-node/server': 0.11.0 - graphql: 16.10.0 + graphql: 17.0.2 lru-cache: 10.4.3 tslib: 2.8.1 - graphql@16.10.0: {} + graphql@17.0.2: {} h3@1.15.11: dependencies: diff --git a/site/package.json b/site/package.json index 9ac5222..3acb121 100644 --- a/site/package.json +++ b/site/package.json @@ -21,7 +21,7 @@ "astro": "^7.2.4", "esbuild": "^0.28.2", "expressive-code-twoslash": "^0.4.0", - "graphql": "^16.3.0", + "graphql": "^17.0.2", "mdast-util-mdx-jsx": "^3.2.0", "remark-shiki-twoslash": "^3.1.3", "tailwindcss": "^4.3.3", diff --git a/test-project/package.json b/test-project/package.json index 099bb71..b6427b8 100644 --- a/test-project/package.json +++ b/test-project/package.json @@ -8,6 +8,6 @@ "@graphql-ts/extend": "workspace:^", "@graphql-ts/schema": "workspace:^", "@types/node": "^22.13.10", - "graphql": "^16.3.0" + "graphql": "^17.0.2" } } From d32c7da557c11c5dfdbf0090fd902be8d73c43ff Mon Sep 17 00:00:00 2001 From: Emma Hamilton Date: Fri, 21 Aug 2026 18:28:54 +1000 Subject: [PATCH 3/4] Fix type compatibility with GraphQL 17 --- .changeset/green-seals-doubt.md | 6 ++++ packages/schema/src/types.d.ts | 57 ++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 .changeset/green-seals-doubt.md diff --git a/.changeset/green-seals-doubt.md b/.changeset/green-seals-doubt.md new file mode 100644 index 0000000..486b121 --- /dev/null +++ b/.changeset/green-seals-doubt.md @@ -0,0 +1,6 @@ +--- +"@graphql-ts/extend": patch +"@graphql-ts/schema": patch +--- + +Add support for `graphql@17` diff --git a/packages/schema/src/types.d.ts b/packages/schema/src/types.d.ts index 3682087..3243e40 100644 --- a/packages/schema/src/types.d.ts +++ b/packages/schema/src/types.d.ts @@ -6,11 +6,14 @@ * @module */ import type { + GraphQLArgumentConfig, GraphQLArgumentExtensions, GraphQLEnumType, GraphQLEnumTypeConfig, + GraphQLFieldConfigMap, GraphQLEnumValueConfig, GraphQLFieldExtensions, + GraphQLFieldMap, GraphQLInputField, GraphQLInputFieldExtensions, GraphQLInputObjectType, @@ -33,6 +36,17 @@ import type { g } from "./g-for-doc-references.ts"; type Maybe = T | null | undefined; +export type GraphQLDefaultInput = GraphQLArgumentConfig["default" & + keyof GraphQLArgumentConfig]; + +export type NativeDefault< + Value, + IsRequired extends boolean = undefined extends Value ? false : true, +> = "default" extends keyof GraphQLArgumentConfig + ? Pick & + (IsRequired extends true ? { default: Value } : { default?: Value }) + : {}; + export type GNullableOutputType = | GScalarType | GObjectType @@ -240,6 +254,9 @@ export class GUnionType extends GraphQLUnionType { > ); resolveType: Maybe>; + toConfig(): Omit, "resolveType"> & { + resolveType?: Maybe>; + }; } export type GUnionTypeConfig< @@ -287,6 +304,7 @@ export class GInterfaceType< Context, > extends GraphQLInterfaceType { declare resolveType: Maybe>; + getFields(): GraphQLFieldMap; constructor( config: Readonly< GInterfaceTypeConfig< @@ -297,8 +315,24 @@ export class GInterfaceType< > > ); - toConfig(): Omit, "fields"> & { - fields: Fields; + toConfig(): Omit< + ReturnType, + "fields" | "resolveType" + > & { + fields: { + [Key in keyof Fields]: Fields[Key] & { + args: { + [Arg in keyof NonNullable]: NativeDefault< + GraphQLDefaultInput, + true + > & { + extensions: Readonly; + }; + }; + extensions: Readonly>; + }; + }; + resolveType?: Maybe>; }; } @@ -452,7 +486,10 @@ export class GEnumType< constructor(config: Readonly>); toConfig(): Omit, "values"> & { values: { - [Name in keyof Values]: Partial>; + [Name in keyof Values]: ReturnType< + GraphQLEnumType["toConfig"] + >["values"][string] & + Partial>; }; }; } @@ -478,6 +515,16 @@ type Flatten = { [K in keyof T]: T[K]; } & {}; +// this is so that on graphql 16 and below where GraphQLNonNull and GraphQLList are structurally compatible +// we make them non-compatible with a get [Symbol.toStringTag]() with a string literal +// but in graphql 17, properties were added to make them incompatible so we don't need to do this anymore +// this means that on graphql 17 GraphQLNonNull and GNonNull are assignable in both directions +// and same for GraphQLList and GList +type GNonNullToStringTag = + GraphQLNonNull extends GraphQLList ? "GraphQLNonNull" : string; +type GListToStringTag = + GraphQLNonNull extends GraphQLList ? "GraphQLList" : string; + /** * A GraphQL non-null type. This should generally be constructed with * {@link g.nonNull}. @@ -513,7 +560,7 @@ type Flatten = { export class GNonNull< Of extends GNullableType, > extends GraphQLNonNull { - get [Symbol.toStringTag](): "GraphQLNonNull"; + get [Symbol.toStringTag](): GNonNullToStringTag; } /** @@ -547,7 +594,7 @@ export class GNonNull< * `GraphQLNonNull` and `GraphQLList` types. */ export class GList> extends GraphQLList { - get [Symbol.toStringTag](): "GraphQLList"; + get [Symbol.toStringTag](): GListToStringTag; } export {}; From a80dec2c7366b76e58b1bc44be6b462b853492bf Mon Sep 17 00:00:00 2001 From: Emma Hamilton Date: Fri, 21 Aug 2026 19:00:58 +1000 Subject: [PATCH 4/4] Tests for GraphQL 17 --- .github/workflows/main.yml | 6 ++- package.json | 1 + test-project/graphql-17/index.test-d.ts | 53 +++++++++++++++++++++++++ test-project/graphql-17/tsconfig.json | 6 +++ test-project/interface-config.test-d.ts | 34 ++++++++++++++++ tsconfig.json | 1 + tsconfig.ts5-7.json | 1 + 7 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 test-project/graphql-17/index.test-d.ts create mode 100644 test-project/graphql-17/tsconfig.json create mode 100644 test-project/interface-config.test-d.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fbc687c..51133eb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - graphql: ["16.0.0", "16.14.2"] + graphql: ["16.0.0", "16.14.2", "17.0.2"] steps: - uses: actions/checkout@main @@ -29,6 +29,10 @@ jobs: - name: Check Types run: pnpm run all:types + - name: Check GraphQL 17 Type Contracts + if: matrix.graphql == '17.0.2' + run: pnpm run graphql17:types + - name: Check GraphQL 16 Type Contracts if: startsWith(matrix.graphql, '16.') run: pnpm run graphql16:types diff --git a/package.json b/package.json index 3ba2a2c..e5356a9 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "types": "tsc", "all:types": "pnpm run /^types.*/ && pnpm -r run types", "graphql16:types": "tsc -p test-project/graphql-16/tsconfig.json && ./node_modules/ts-5-7/bin/tsc -p test-project/graphql-16/tsconfig.json", + "graphql17:types": "tsc -p test-project/graphql-17/tsconfig.json && ./node_modules/ts-5-7/bin/tsc -p test-project/graphql-17/tsconfig.json", "lint": "oxlint . && oxfmt --check .", "site": "cd site && pnpm dev", "build": "preconstruct build", diff --git a/test-project/graphql-17/index.test-d.ts b/test-project/graphql-17/index.test-d.ts new file mode 100644 index 0000000..7f31d38 --- /dev/null +++ b/test-project/graphql-17/index.test-d.ts @@ -0,0 +1,53 @@ +import type { + GArg, + GInputObjectType, + GInterfaceField, + GInterfaceType, + GList, + GNonNull, + GScalarType, + GUnionType, +} from "@graphql-ts/schema"; +import type { + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLUnionType, +} from "graphql"; + +type Invariant = (value: T) => T; +function assertCompatible() {} + +type Source = { id: string }; +type Context = { requestId: string }; +type Scalar = GScalarType; + +assertCompatible< + Invariant>, + Invariant> +>(); +assertCompatible< + Invariant>, + Invariant> +>(); +assertCompatible< + Invariant>, + Invariant> +>(); +assertCompatible>, Invariant>>(); +assertCompatible< + Invariant, + Invariant>, boolean>> +>(); + +type InterfaceFields = { + id: GInterfaceField<{}, Scalar, Context>; +}; +type PreciseInterface = GInterfaceType; +assertCompatible, PreciseInterface>(); +assertCompatible< + PreciseInterface, + // @ts-expect-error precise interface fields are GraphQL-TS-only information + GraphQLInterfaceType +>(); diff --git a/test-project/graphql-17/tsconfig.json b/test-project/graphql-17/tsconfig.json new file mode 100644 index 0000000..3ee076f --- /dev/null +++ b/test-project/graphql-17/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { "types": ["node"] }, + "include": ["./*.ts"], + "exclude": [] +} diff --git a/test-project/interface-config.test-d.ts b/test-project/interface-config.test-d.ts new file mode 100644 index 0000000..b27fba1 --- /dev/null +++ b/test-project/interface-config.test-d.ts @@ -0,0 +1,34 @@ +import { gWithContext } from "@graphql-ts/schema"; +import type { GraphQLInterfaceType } from "graphql"; + +const g = gWithContext(); +const node = g.interface<{ id: string }>()({ + name: "Node", + fields: { + lookup: g.interfaceField({ + type: g.String, + args: { id: g.arg({ type: g.nonNull(g.ID) }) }, + }), + label: g.interfaceField({ type: g.String, args: {} }), + }, +}); + +const config = node.toConfig(); +config.fields.lookup.args.id.type; +// @ts-expect-error only declared argument names may be accessed +config.fields.lookup.args.typo.type; +// @ts-expect-error fields without arguments have no argument names +config.fields.label.args.typo; + +type Invariant = (value: T) => T; +function assertCompatible() {} + +assertCompatible< + Invariant<"id">, + Invariant +>(); +assertCompatible< + Invariant, + Invariant +>(); +assertCompatible, typeof config>(); diff --git a/tsconfig.json b/tsconfig.json index 7e1f20c..29dcddc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,6 +19,7 @@ "site/**", "**/node_modules/**", "test-project/typescript-5-7.test-d.ts", + "test-project/graphql-17/**", "test-project/graphql-16/**" ] } diff --git a/tsconfig.ts5-7.json b/tsconfig.ts5-7.json index c223d93..2da0e6f 100644 --- a/tsconfig.ts5-7.json +++ b/tsconfig.ts5-7.json @@ -11,6 +11,7 @@ "site/**", "**/node_modules/**", "test-project/typescript-6.test-d.ts", + "test-project/graphql-17/**", "test-project/graphql-16/**" ] }