From 7ee63b0672783d31141a967f982d407369930ae6 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Sun, 28 Jun 2020 15:36:23 +0100 Subject: [PATCH] Change type of extensions from anonymous Record to named interfaces (#2465) --- integrationTests/ts/index.ts | 43 +++++++- src/index.d.ts | 12 +++ src/type/definition.d.ts | 194 ++++++++++++++++++++++++++++++----- src/type/directives.d.ts | 20 +++- src/type/index.d.ts | 12 +++ src/type/schema.d.ts | 21 +++- 6 files changed, 268 insertions(+), 34 deletions(-) diff --git a/integrationTests/ts/index.ts b/integrationTests/ts/index.ts index 7781e09b7f..eb989414b3 100644 --- a/integrationTests/ts/index.ts +++ b/integrationTests/ts/index.ts @@ -2,17 +2,58 @@ import { GraphQLString, GraphQLSchema, GraphQLObjectType } from 'graphql/type'; import { ExecutionResult } from 'graphql/execution'; import { graphqlSync } from 'graphql'; +interface SomeExtension { + number: number; + string: string; +} + +const example: SomeExtension = { + number: 42, + string: 'Meaning of life', +}; + +// FIXME: The following code block requires a version of TypeScript >= 3.2 +/* + +declare module 'graphql' { + interface GraphQLObjectTypeExtensions { + someObjectExtension?: SomeExtension; + } + interface GraphQLFieldExtensions< + TSource, + TContext, + TArgs = { [argName: string]: any } + > { + someFieldExtension?: SomeExtension; + } + interface GraphQLArgumentExtensions { + someArgumentExtension?: SomeExtension; + } +} +*/ + const queryType: GraphQLObjectType = new GraphQLObjectType({ name: 'Query', fields: { sayHi: { type: GraphQLString, args: { - who: { type: GraphQLString }, + who: { + type: GraphQLString, + extensions: { + someArgumentExtension: example, + }, + }, }, resolve: (_root, args) => 'Hello ' + (args.who || 'World'), + extensions: { + someFieldExtension: example, + }, }, }, + extensions: { + someObjectExtension: example, + }, }); const schema: GraphQLSchema = new GraphQLSchema({ diff --git a/src/index.d.ts b/src/index.d.ts index 5c14390edd..6273448f22 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -139,32 +139,44 @@ export { GraphQLNamedType, Thunk, GraphQLSchemaConfig, + GraphQLSchemaExtensions, GraphQLDirectiveConfig, + GraphQLDirectiveExtensions, GraphQLArgument, GraphQLArgumentConfig, + GraphQLArgumentExtensions, GraphQLEnumTypeConfig, + GraphQLEnumTypeExtensions, GraphQLEnumValue, GraphQLEnumValueConfig, + GraphQLEnumValueExtensions, GraphQLEnumValueConfigMap, GraphQLField, GraphQLFieldConfig, + GraphQLFieldExtensions, GraphQLFieldConfigArgumentMap, GraphQLFieldConfigMap, GraphQLFieldMap, GraphQLFieldResolver, GraphQLInputField, GraphQLInputFieldConfig, + GraphQLInputFieldExtensions, GraphQLInputFieldConfigMap, GraphQLInputFieldMap, GraphQLInputObjectTypeConfig, + GraphQLInputObjectTypeExtensions, GraphQLInterfaceTypeConfig, + GraphQLInterfaceTypeExtensions, GraphQLIsTypeOfFn, GraphQLObjectTypeConfig, + GraphQLObjectTypeExtensions, GraphQLResolveInfo, ResponsePath, GraphQLScalarTypeConfig, + GraphQLScalarTypeExtensions, GraphQLTypeResolver, GraphQLUnionTypeConfig, + GraphQLUnionTypeExtensions, GraphQLScalarSerializer, GraphQLScalarValueParser, GraphQLScalarLiteralParser, diff --git a/src/type/definition.d.ts b/src/type/definition.d.ts index 7036861aab..aa3177a69d 100644 --- a/src/type/definition.d.ts +++ b/src/type/definition.d.ts @@ -275,6 +275,19 @@ export function getNamedType(type: GraphQLType): GraphQLNamedType; */ export type Thunk = (() => T) | T; +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLScalarTypeExtensions { + [attributeName: string]: any; +} + /** * Scalar Type Definition * @@ -299,7 +312,7 @@ export class GraphQLScalarType { serialize: GraphQLScalarSerializer; parseValue: GraphQLScalarValueParser; parseLiteral: GraphQLScalarLiteralParser; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -310,7 +323,7 @@ export class GraphQLScalarType { serialize: GraphQLScalarSerializer; parseValue: GraphQLScalarValueParser; parseLiteral: GraphQLScalarLiteralParser; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -340,11 +353,27 @@ export interface GraphQLScalarTypeConfig { parseValue?: GraphQLScalarValueParser; // Parses an externally provided literal value to use as an input. parseLiteral?: GraphQLScalarLiteralParser; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; extensionASTNodes?: Maybe>; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + * + * We've provided these template arguments because this is an open type and + * you may find them useful. + */ +export interface GraphQLObjectTypeExtensions { + [attributeName: string]: any; +} + /** * Object Type Definition * @@ -386,7 +415,7 @@ export class GraphQLObjectType { name: string; description: Maybe; isTypeOf: Maybe>; - extensions: Maybe>>; + extensions: Maybe>>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -398,7 +427,7 @@ export class GraphQLObjectType { toConfig(): GraphQLObjectTypeConfig & { interfaces: Array; fields: GraphQLFieldConfigMap; - extensions: Maybe>>; + extensions: Maybe>>; extensionASTNodes: ReadonlyArray; }; @@ -417,7 +446,7 @@ export interface GraphQLObjectTypeConfig { interfaces?: Thunk>>; fields: Thunk>; isTypeOf?: Maybe>; - extensions?: Maybe>>; + extensions?: Maybe>>; astNode?: Maybe; extensionASTNodes?: Maybe>; } @@ -459,6 +488,26 @@ export interface GraphQLResolveInfo { readonly variableValues: { [variableName: string]: any }; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + * + * We've provided these template arguments because this is an open type and + * you may find them useful. + */ +export interface GraphQLFieldExtensions< + TSource, + TContext, + TArgs = { [argName: string]: any } +> { + [attributeName: string]: any; +} + export interface GraphQLFieldConfig< TSource, TContext, @@ -470,7 +519,9 @@ export interface GraphQLFieldConfig< resolve?: GraphQLFieldResolver; subscribe?: GraphQLFieldResolver; deprecationReason?: Maybe; - extensions?: Maybe>>; + extensions?: Maybe< + Readonly> + >; astNode?: Maybe; } @@ -478,11 +529,24 @@ export interface GraphQLFieldConfigArgumentMap { [key: string]: GraphQLArgumentConfig; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLArgumentExtensions { + [attributeName: string]: any; +} + export interface GraphQLArgumentConfig { description?: Maybe; type: GraphQLInputType; defaultValue?: any; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; } @@ -503,7 +567,7 @@ export interface GraphQLField< subscribe?: GraphQLFieldResolver; isDeprecated: boolean; deprecationReason: Maybe; - extensions: Maybe>>; + extensions: Maybe>>; astNode?: Maybe; } @@ -512,7 +576,7 @@ export interface GraphQLArgument { description: Maybe; type: GraphQLInputType; defaultValue: any; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; } @@ -522,6 +586,19 @@ export interface GraphQLFieldMap { [key: string]: GraphQLField; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLInterfaceTypeExtensions { + [attributeName: string]: any; +} + /** * Interface Type Definition * @@ -544,7 +621,7 @@ export class GraphQLInterfaceType { name: string; description: Maybe; resolveType: Maybe>; - extensions: Maybe>>; + extensions: Maybe>; astNode?: Maybe; extensionASTNodes: Maybe>; @@ -555,7 +632,7 @@ export class GraphQLInterfaceType { toConfig(): GraphQLInterfaceTypeConfig & { interfaces: Array; fields: GraphQLFieldConfigMap; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -575,11 +652,24 @@ export interface GraphQLInterfaceTypeConfig { * Object type. */ resolveType?: Maybe>; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; extensionASTNodes?: Maybe>; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLUnionTypeExtensions { + [attributeName: string]: any; +} + /** * Union Type Definition * @@ -607,7 +697,7 @@ export class GraphQLUnionType { name: string; description: Maybe; resolveType: Maybe>; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -616,7 +706,7 @@ export class GraphQLUnionType { toConfig(): GraphQLUnionTypeConfig & { types: Array; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -635,11 +725,24 @@ export interface GraphQLUnionTypeConfig { * Object type. */ resolveType?: Maybe>; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; extensionASTNodes?: Maybe>; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLEnumTypeExtensions { + [attributeName: string]: any; +} + /** * Enum Type Definition * @@ -664,7 +767,7 @@ export interface GraphQLUnionTypeConfig { export class GraphQLEnumType { name: string; description: Maybe; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -679,7 +782,7 @@ export class GraphQLEnumType { ): Maybe; toConfig(): GraphQLEnumTypeConfig & { - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -692,7 +795,7 @@ export interface GraphQLEnumTypeConfig { name: string; description?: Maybe; values: GraphQLEnumValueConfigMap; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; extensionASTNodes?: Maybe>; } @@ -701,11 +804,24 @@ export interface GraphQLEnumValueConfigMap { [key: string]: GraphQLEnumValueConfig; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLEnumValueExtensions { + [attributeName: string]: any; +} + export interface GraphQLEnumValueConfig { description?: Maybe; value?: any; deprecationReason?: Maybe; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; } @@ -715,10 +831,23 @@ export interface GraphQLEnumValue { value: any; isDeprecated: boolean; deprecationReason: Maybe; - extensions: Maybe>>; + extensions: Maybe>; astNode?: Maybe; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLInputObjectTypeExtensions { + [attributeName: string]: any; +} + /** * Input Object Type Definition * @@ -742,7 +871,7 @@ export interface GraphQLEnumValue { export class GraphQLInputObjectType { name: string; description: Maybe; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -751,7 +880,7 @@ export class GraphQLInputObjectType { toConfig(): GraphQLInputObjectTypeConfig & { fields: GraphQLInputFieldConfigMap; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -764,16 +893,29 @@ export interface GraphQLInputObjectTypeConfig { name: string; description?: Maybe; fields: Thunk; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; extensionASTNodes?: Maybe>; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLInputFieldExtensions { + [attributeName: string]: any; +} + export interface GraphQLInputFieldConfig { description?: Maybe; type: GraphQLInputType; defaultValue?: any; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; } @@ -786,7 +928,7 @@ export interface GraphQLInputField { description?: Maybe; type: GraphQLInputType; defaultValue?: any; - extensions: Maybe>>; + extensions: Maybe>; astNode?: Maybe; } diff --git a/src/type/directives.d.ts b/src/type/directives.d.ts index 0d062e6a9c..2c6de77b1d 100644 --- a/src/type/directives.d.ts +++ b/src/type/directives.d.ts @@ -13,6 +13,20 @@ import { GraphQLFieldConfigArgumentMap, GraphQLArgument } from './definition'; */ export function isDirective(directive: any): directive is GraphQLDirective; export function assertDirective(directive: any): GraphQLDirective; + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLDirectiveExtensions { + [attributeName: string]: any; +} + /** * Directives are used by the GraphQL runtime as a way of modifying execution * behavior. Type system creators will usually not create these directly. @@ -23,7 +37,7 @@ export class GraphQLDirective { locations: Array; isRepeatable: boolean; args: Array; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; constructor(config: Readonly); @@ -31,7 +45,7 @@ export class GraphQLDirective { toConfig(): GraphQLDirectiveConfig & { args: GraphQLFieldConfigArgumentMap; isRepeatable: boolean; - extensions: Maybe>>; + extensions: Maybe>; }; toString(): string; @@ -45,7 +59,7 @@ export interface GraphQLDirectiveConfig { locations: Array; args?: Maybe; isRepeatable?: Maybe; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; } diff --git a/src/type/index.d.ts b/src/type/index.d.ts index 3454d8e36b..9686f413b7 100644 --- a/src/type/index.d.ts +++ b/src/type/index.d.ts @@ -8,6 +8,7 @@ export { // GraphQL Schema definition GraphQLSchema, GraphQLSchemaConfig, + GraphQLSchemaExtensions, } from './schema'; export { @@ -75,28 +76,38 @@ export { Thunk, GraphQLArgument, GraphQLArgumentConfig, + GraphQLArgumentExtensions, GraphQLEnumTypeConfig, + GraphQLEnumTypeExtensions, GraphQLEnumValue, GraphQLEnumValueConfig, GraphQLEnumValueConfigMap, + GraphQLEnumValueExtensions, GraphQLField, GraphQLFieldConfig, GraphQLFieldConfigArgumentMap, GraphQLFieldConfigMap, + GraphQLFieldExtensions, GraphQLFieldMap, GraphQLFieldResolver, GraphQLInputField, GraphQLInputFieldConfig, GraphQLInputFieldConfigMap, + GraphQLInputFieldExtensions, GraphQLInputFieldMap, GraphQLInputObjectTypeConfig, + GraphQLInputObjectTypeExtensions, GraphQLInterfaceTypeConfig, + GraphQLInterfaceTypeExtensions, GraphQLIsTypeOfFn, GraphQLObjectTypeConfig, + GraphQLObjectTypeExtensions, GraphQLResolveInfo, GraphQLScalarTypeConfig, + GraphQLScalarTypeExtensions, GraphQLTypeResolver, GraphQLUnionTypeConfig, + GraphQLUnionTypeExtensions, GraphQLScalarSerializer, GraphQLScalarValueParser, GraphQLScalarLiteralParser, @@ -120,6 +131,7 @@ export { DEFAULT_DEPRECATION_REASON, // type GraphQLDirectiveConfig, + GraphQLDirectiveExtensions, } from './directives'; // Common built-in scalar instances. diff --git a/src/type/schema.d.ts b/src/type/schema.d.ts index 1ae844362a..4f759f9f27 100644 --- a/src/type/schema.d.ts +++ b/src/type/schema.d.ts @@ -19,6 +19,19 @@ import { export function isSchema(schema: any): schema is GraphQLSchema; export function assertSchema(schema: any): GraphQLSchema; +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLSchemaExtensions { + [attributeName: string]: any; +} + /** * Schema Definition * @@ -47,7 +60,7 @@ export function assertSchema(schema: any): GraphQLSchema; */ export class GraphQLSchema { description: Maybe; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -83,7 +96,7 @@ export class GraphQLSchema { toConfig(): GraphQLSchemaConfig & { types: Array; directives: Array; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; assumeValid: boolean; }; @@ -116,7 +129,7 @@ export interface GraphQLSchemaConfig extends GraphQLSchemaValidationOptions { subscription?: Maybe; types?: Maybe>; directives?: Maybe>; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; extensionASTNodes?: Maybe>; } @@ -128,7 +141,7 @@ export interface GraphQLSchemaNormalizedConfig extends GraphQLSchemaConfig { description: Maybe; types: Array; directives: Array; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: Maybe>; assumeValid: boolean; }