From 3450c464b702b9efa03aaf5058184e136fe434c7 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Tue, 15 Nov 2016 15:00:47 -0800 Subject: [PATCH] Add TContext to field resolvers This adds additional type information to field resolvers, such that source and context get slightly more appropriate types. This partially improves one of the issues raised in #554 --- src/execution/__tests__/mutations-test.js | 16 +++--- src/execution/execute.js | 14 +++--- src/execution/values.js | 2 +- src/type/definition.js | 50 +++++++++---------- src/type/introspection.js | 6 +-- src/utilities/TypeInfo.js | 6 +-- .../rules/OverlappingFieldsCanBeMerged.js | 2 +- src/validation/validate.js | 2 +- 8 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/execution/__tests__/mutations-test.js b/src/execution/__tests__/mutations-test.js index fffe353ff6..8f21b06115 100644 --- a/src/execution/__tests__/mutations-test.js +++ b/src/execution/__tests__/mutations-test.js @@ -79,30 +79,30 @@ const schema = new GraphQLSchema({ immediatelyChangeTheNumber: { type: numberHolderType, args: { newNumber: { type: GraphQLInt } }, - resolve: (function (obj, { newNumber }) { + resolve(obj, { newNumber }) { return obj.immediatelyChangeTheNumber(newNumber); - }: any) + } }, promiseToChangeTheNumber: { type: numberHolderType, args: { newNumber: { type: GraphQLInt } }, - resolve: (function (obj, { newNumber }) { + resolve(obj, { newNumber }) { return obj.promiseToChangeTheNumber(newNumber); - }: any) + } }, failToChangeTheNumber: { type: numberHolderType, args: { newNumber: { type: GraphQLInt } }, - resolve: (function (obj, { newNumber }) { + resolve(obj, { newNumber }) { return obj.failToChangeTheNumber(newNumber); - }: any) + } }, promiseAndFailToChangeTheNumber: { type: numberHolderType, args: { newNumber: { type: GraphQLInt } }, - resolve: (function (obj, { newNumber }) { + resolve(obj, { newNumber }) { return obj.promiseAndFailToChangeTheNumber(newNumber); - }: any) + } } }, name: 'Mutation', diff --git a/src/execution/execute.js b/src/execution/execute.js index 612e8d91e8..836747c429 100644 --- a/src/execution/execute.js +++ b/src/execution/execute.js @@ -626,13 +626,13 @@ function resolveField( // Isolates the "ReturnOrAbrupt" behavior to not de-opt the `resolveField` // function. Returns the result of resolveFn or the abrupt-return Error object. -function resolveOrError( +function resolveOrError( exeContext: ExecutionContext, - fieldDef: GraphQLField, + fieldDef: GraphQLField, fieldNode: FieldNode, - resolveFn: GraphQLFieldResolver<*>, - source: mixed, - context: mixed, + resolveFn: GraphQLFieldResolver, + source: TSource, + context: TContext, info: GraphQLResolveInfo ): Error | mixed { try { @@ -1042,7 +1042,7 @@ function defaultResolveTypeFn( * and returns it as the result, or if it's a function, returns the result * of calling that function while passing along args and context. */ -export const defaultFieldResolver: GraphQLFieldResolver = +export const defaultFieldResolver: GraphQLFieldResolver = function (source, args, context, { fieldName }) { // ensure source is a value for which property access is acceptable. if (typeof source === 'object' || typeof source === 'function') { @@ -1077,7 +1077,7 @@ function getFieldDef( schema: GraphQLSchema, parentType: GraphQLObjectType, fieldName: string -): ?GraphQLField { +): ?GraphQLField<*, *> { if (fieldName === SchemaMetaFieldDef.name && schema.getQueryType() === parentType) { return SchemaMetaFieldDef; diff --git a/src/execution/values.js b/src/execution/values.js index 90d2484312..9c0b340148 100644 --- a/src/execution/values.js +++ b/src/execution/values.js @@ -104,7 +104,7 @@ export function getVariableValues( * definitions and list of argument AST nodes. */ export function getArgumentValues( - def: GraphQLField | GraphQLDirective, + def: GraphQLField<*, *> | GraphQLDirective, node: FieldNode | DirectiveNode, variableValues?: ?{ [key: string]: mixed } ): { [key: string]: mixed } { diff --git a/src/type/definition.js b/src/type/definition.js index ccd00b0ded..d4365fb3b4 100644 --- a/src/type/definition.js +++ b/src/type/definition.js @@ -368,11 +368,11 @@ export class GraphQLObjectType { description: ?string; isTypeOf: ?GraphQLIsTypeOfFn; - _typeConfig: GraphQLObjectTypeConfig<*>; - _fields: GraphQLFieldMap; + _typeConfig: GraphQLObjectTypeConfig<*, *>; + _fields: GraphQLFieldMap<*, *>; _interfaces: Array; - constructor(config: GraphQLObjectTypeConfig<*>) { + constructor(config: GraphQLObjectTypeConfig<*, *>) { invariant(config.name, 'Type must be named.'); assertValidName(config.name); this.name = config.name; @@ -387,7 +387,7 @@ export class GraphQLObjectType { this._typeConfig = config; } - getFields(): GraphQLFieldMap { + getFields(): GraphQLFieldMap<*, *> { return this._fields || (this._fields = defineFieldMap(this, this._typeConfig.fields) ); @@ -436,10 +436,10 @@ function defineInterfaces( return interfaces; } -function defineFieldMap( +function defineFieldMap( type: GraphQLNamedType, - fieldsThunk: Thunk> -): GraphQLFieldMap { + fieldsThunk: Thunk> +): GraphQLFieldMap { const fieldMap = resolveThunk(fieldsThunk); invariant( isPlainObj(fieldMap), @@ -507,10 +507,10 @@ function isPlainObj(obj) { return obj && typeof obj === 'object' && !Array.isArray(obj); } -export type GraphQLObjectTypeConfig = { +export type GraphQLObjectTypeConfig = { name: string; interfaces?: Thunk>; - fields: Thunk>; + fields: Thunk>; isTypeOf?: ?GraphQLIsTypeOfFn; description?: ?string }; @@ -527,10 +527,10 @@ export type GraphQLIsTypeOfFn = ( info: GraphQLResolveInfo ) => boolean; -export type GraphQLFieldResolver = ( +export type GraphQLFieldResolver = ( source: TSource, args: {[argName: string]: mixed}, - context: mixed, + context: TContext, info: GraphQLResolveInfo ) => mixed; @@ -549,10 +549,10 @@ export type GraphQLResolveInfo = { export type ResponsePath = { prev: ResponsePath, key: string | number } | void; -export type GraphQLFieldConfig = { +export type GraphQLFieldConfig = { type: GraphQLOutputType; args?: GraphQLFieldConfigArgumentMap; - resolve?: GraphQLFieldResolver; + resolve?: GraphQLFieldResolver; deprecationReason?: ?string; description?: ?string; }; @@ -567,16 +567,16 @@ export type GraphQLArgumentConfig = { description?: ?string; }; -export type GraphQLFieldConfigMap = { - [fieldName: string]: GraphQLFieldConfig; +export type GraphQLFieldConfigMap = { + [fieldName: string]: GraphQLFieldConfig; }; -export type GraphQLField = { +export type GraphQLField = { name: string; description: ?string; type: GraphQLOutputType; args: Array; - resolve?: GraphQLFieldResolver<*>; + resolve?: GraphQLFieldResolver; isDeprecated?: boolean; deprecationReason?: ?string; }; @@ -588,8 +588,8 @@ export type GraphQLArgument = { description?: ?string; }; -export type GraphQLFieldMap = { - [fieldName: string]: GraphQLField; +export type GraphQLFieldMap = { + [fieldName: string]: GraphQLField; }; @@ -617,10 +617,10 @@ export class GraphQLInterfaceType { description: ?string; resolveType: ?GraphQLTypeResolver; - _typeConfig: GraphQLInterfaceTypeConfig; - _fields: GraphQLFieldMap; + _typeConfig: GraphQLInterfaceTypeConfig<*, *>; + _fields: GraphQLFieldMap<*, *>; - constructor(config: GraphQLInterfaceTypeConfig) { + constructor(config: GraphQLInterfaceTypeConfig<*, *>) { invariant(config.name, 'Type must be named.'); assertValidName(config.name); this.name = config.name; @@ -635,7 +635,7 @@ export class GraphQLInterfaceType { this._typeConfig = config; } - getFields(): GraphQLFieldMap { + getFields(): GraphQLFieldMap<*, *> { return this._fields || (this._fields = defineFieldMap(this, this._typeConfig.fields)); } @@ -645,9 +645,9 @@ export class GraphQLInterfaceType { } } -export type GraphQLInterfaceTypeConfig = { +export type GraphQLInterfaceTypeConfig = { name: string, - fields: Thunk>, + fields: Thunk>, /** * Optionally provide a custom type resolver function. If one is not provided, * the default implementation will call `isTypeOf` on each implementing diff --git a/src/type/introspection.js b/src/type/introspection.js index cbd23f15e8..d9a1cd202a 100644 --- a/src/type/introspection.js +++ b/src/type/introspection.js @@ -418,7 +418,7 @@ export const __TypeKind = new GraphQLEnumType({ * so the format for args is different. */ -export const SchemaMetaFieldDef: GraphQLField = { +export const SchemaMetaFieldDef: GraphQLField<*, *> = { name: '__schema', type: new GraphQLNonNull(__Schema), description: 'Access the current type schema of this server.', @@ -426,7 +426,7 @@ export const SchemaMetaFieldDef: GraphQLField = { resolve: (source, args, context, { schema }) => schema }; -export const TypeMetaFieldDef: GraphQLField = { +export const TypeMetaFieldDef: GraphQLField<*, *> = { name: '__type', type: __Type, description: 'Request the type information of a single type.', @@ -437,7 +437,7 @@ export const TypeMetaFieldDef: GraphQLField = { schema.getType(((name: any): string)) }; -export const TypeNameMetaFieldDef: GraphQLField = { +export const TypeNameMetaFieldDef: GraphQLField<*, *> = { name: '__typename', type: new GraphQLNonNull(GraphQLString), description: 'The name of the current Object type at runtime.', diff --git a/src/utilities/TypeInfo.js b/src/utilities/TypeInfo.js index af4befc06d..298c21825c 100644 --- a/src/utilities/TypeInfo.js +++ b/src/utilities/TypeInfo.js @@ -49,7 +49,7 @@ export class TypeInfo { _typeStack: Array; _parentTypeStack: Array; _inputTypeStack: Array; - _fieldDefStack: Array; + _fieldDefStack: Array>; _directive: ?GraphQLDirective; _argument: ?GraphQLArgument; _getFieldDef: typeof getFieldDef; @@ -89,7 +89,7 @@ export class TypeInfo { } } - getFieldDef(): ?GraphQLField { + getFieldDef(): ?GraphQLField<*, *> { if (this._fieldDefStack.length > 0) { return this._fieldDefStack[this._fieldDefStack.length - 1]; } @@ -226,7 +226,7 @@ function getFieldDef( schema: GraphQLSchema, parentType: GraphQLType, fieldNode: FieldNode -): ?GraphQLField { +): ?GraphQLField<*, *> { const name = fieldNode.name.value; if (name === SchemaMetaFieldDef.name && schema.getQueryType() === parentType) { diff --git a/src/validation/rules/OverlappingFieldsCanBeMerged.js b/src/validation/rules/OverlappingFieldsCanBeMerged.js index 89d9e6e4ec..d6ebe56588 100644 --- a/src/validation/rules/OverlappingFieldsCanBeMerged.js +++ b/src/validation/rules/OverlappingFieldsCanBeMerged.js @@ -98,7 +98,7 @@ type ConflictReason = [ string, ConflictReasonMessage ]; // Reason is a string, or a nested list of conflicts. type ConflictReasonMessage = string | Array; // Tuple defining a field node in a context. -type NodeAndDef = [ GraphQLCompositeType, FieldNode, ?GraphQLField ]; +type NodeAndDef = [ GraphQLCompositeType, FieldNode, ?GraphQLField<*, *> ]; // Map of array of those. type NodeAndDefCollection = { [key: string]: Array }; diff --git a/src/validation/validate.js b/src/validation/validate.js index d85bbbcda7..f97233f0e8 100644 --- a/src/validation/validate.js +++ b/src/validation/validate.js @@ -240,7 +240,7 @@ export class ValidationContext { return this._typeInfo.getInputType(); } - getFieldDef(): ?GraphQLField { + getFieldDef(): ?GraphQLField<*, *> { return this._typeInfo.getFieldDef(); }