Skip to content

Commit

Permalink
Add TContext to field resolvers
Browse files Browse the repository at this point in the history
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
  • Loading branch information
leebyron committed Nov 15, 2016
1 parent 1af8e9b commit 3450c46
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 49 deletions.
16 changes: 8 additions & 8 deletions src/execution/__tests__/mutations-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
14 changes: 7 additions & 7 deletions src/execution/execute.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<TSource, TContext>(
exeContext: ExecutionContext,
fieldDef: GraphQLField,
fieldDef: GraphQLField<TSource, TContext>,
fieldNode: FieldNode,
resolveFn: GraphQLFieldResolver<*>,
source: mixed,
context: mixed,
resolveFn: GraphQLFieldResolver<TSource, TContext>,
source: TSource,
context: TContext,
info: GraphQLResolveInfo
): Error | mixed {
try {
Expand Down Expand Up @@ -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<any> =
export const defaultFieldResolver: GraphQLFieldResolver<any, *> =
function (source, args, context, { fieldName }) {
// ensure source is a value for which property access is acceptable.
if (typeof source === 'object' || typeof source === 'function') {
Expand Down Expand Up @@ -1077,7 +1077,7 @@ function getFieldDef(
schema: GraphQLSchema,
parentType: GraphQLObjectType,
fieldName: string
): ?GraphQLField {
): ?GraphQLField<*, *> {
if (fieldName === SchemaMetaFieldDef.name &&
schema.getQueryType() === parentType) {
return SchemaMetaFieldDef;
Expand Down
2 changes: 1 addition & 1 deletion src/execution/values.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 } {
Expand Down
50 changes: 25 additions & 25 deletions src/type/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,11 @@ export class GraphQLObjectType {
description: ?string;
isTypeOf: ?GraphQLIsTypeOfFn;

_typeConfig: GraphQLObjectTypeConfig<*>;
_fields: GraphQLFieldMap;
_typeConfig: GraphQLObjectTypeConfig<*, *>;
_fields: GraphQLFieldMap<*, *>;
_interfaces: Array<GraphQLInterfaceType>;

constructor(config: GraphQLObjectTypeConfig<*>) {
constructor(config: GraphQLObjectTypeConfig<*, *>) {
invariant(config.name, 'Type must be named.');
assertValidName(config.name);
this.name = config.name;
Expand All @@ -387,7 +387,7 @@ export class GraphQLObjectType {
this._typeConfig = config;
}

getFields(): GraphQLFieldMap {
getFields(): GraphQLFieldMap<*, *> {
return this._fields || (this._fields =
defineFieldMap(this, this._typeConfig.fields)
);
Expand Down Expand Up @@ -436,10 +436,10 @@ function defineInterfaces(
return interfaces;
}

function defineFieldMap(
function defineFieldMap<TSource, TContext>(
type: GraphQLNamedType,
fieldsThunk: Thunk<GraphQLFieldConfigMap<*>>
): GraphQLFieldMap {
fieldsThunk: Thunk<GraphQLFieldConfigMap<TSource, TContext>>
): GraphQLFieldMap<TSource, TContext> {
const fieldMap = resolveThunk(fieldsThunk);
invariant(
isPlainObj(fieldMap),
Expand Down Expand Up @@ -507,10 +507,10 @@ function isPlainObj(obj) {
return obj && typeof obj === 'object' && !Array.isArray(obj);
}

export type GraphQLObjectTypeConfig<TSource> = {
export type GraphQLObjectTypeConfig<TSource, TContext> = {
name: string;
interfaces?: Thunk<?Array<GraphQLInterfaceType>>;
fields: Thunk<GraphQLFieldConfigMap<TSource>>;
fields: Thunk<GraphQLFieldConfigMap<TSource, TContext>>;
isTypeOf?: ?GraphQLIsTypeOfFn;
description?: ?string
};
Expand All @@ -527,10 +527,10 @@ export type GraphQLIsTypeOfFn = (
info: GraphQLResolveInfo
) => boolean;

export type GraphQLFieldResolver<TSource> = (
export type GraphQLFieldResolver<TSource, TContext> = (
source: TSource,
args: {[argName: string]: mixed},
context: mixed,
context: TContext,
info: GraphQLResolveInfo
) => mixed;

Expand All @@ -549,10 +549,10 @@ export type GraphQLResolveInfo = {

export type ResponsePath = { prev: ResponsePath, key: string | number } | void;

export type GraphQLFieldConfig<TSource> = {
export type GraphQLFieldConfig<TSource, TContext> = {
type: GraphQLOutputType;
args?: GraphQLFieldConfigArgumentMap;
resolve?: GraphQLFieldResolver<TSource>;
resolve?: GraphQLFieldResolver<TSource, TContext>;
deprecationReason?: ?string;
description?: ?string;
};
Expand All @@ -567,16 +567,16 @@ export type GraphQLArgumentConfig = {
description?: ?string;
};

export type GraphQLFieldConfigMap<TSource> = {
[fieldName: string]: GraphQLFieldConfig<TSource>;
export type GraphQLFieldConfigMap<TSource, TContext> = {
[fieldName: string]: GraphQLFieldConfig<TSource, TContext>;
};

export type GraphQLField = {
export type GraphQLField<TSource, TContext> = {
name: string;
description: ?string;
type: GraphQLOutputType;
args: Array<GraphQLArgument>;
resolve?: GraphQLFieldResolver<*>;
resolve?: GraphQLFieldResolver<TSource, TContext>;
isDeprecated?: boolean;
deprecationReason?: ?string;
};
Expand All @@ -588,8 +588,8 @@ export type GraphQLArgument = {
description?: ?string;
};

export type GraphQLFieldMap = {
[fieldName: string]: GraphQLField;
export type GraphQLFieldMap<TSource, TContext> = {
[fieldName: string]: GraphQLField<TSource, TContext>;
};


Expand Down Expand Up @@ -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;
Expand All @@ -635,7 +635,7 @@ export class GraphQLInterfaceType {
this._typeConfig = config;
}

getFields(): GraphQLFieldMap {
getFields(): GraphQLFieldMap<*, *> {
return this._fields ||
(this._fields = defineFieldMap(this, this._typeConfig.fields));
}
Expand All @@ -645,9 +645,9 @@ export class GraphQLInterfaceType {
}
}

export type GraphQLInterfaceTypeConfig = {
export type GraphQLInterfaceTypeConfig<TSource, TContext> = {
name: string,
fields: Thunk<GraphQLFieldConfigMap<mixed>>,
fields: Thunk<GraphQLFieldConfigMap<TSource, TContext>>,
/**
* Optionally provide a custom type resolver function. If one is not provided,
* the default implementation will call `isTypeOf` on each implementing
Expand Down
6 changes: 3 additions & 3 deletions src/type/introspection.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,15 +418,15 @@ 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.',
args: [],
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.',
Expand All @@ -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.',
Expand Down
6 changes: 3 additions & 3 deletions src/utilities/TypeInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class TypeInfo {
_typeStack: Array<?GraphQLOutputType>;
_parentTypeStack: Array<?GraphQLCompositeType>;
_inputTypeStack: Array<?GraphQLInputType>;
_fieldDefStack: Array<?GraphQLField>;
_fieldDefStack: Array<?GraphQLField<*, *>>;
_directive: ?GraphQLDirective;
_argument: ?GraphQLArgument;
_getFieldDef: typeof getFieldDef;
Expand Down Expand Up @@ -89,7 +89,7 @@ export class TypeInfo {
}
}

getFieldDef(): ?GraphQLField {
getFieldDef(): ?GraphQLField<*, *> {
if (this._fieldDefStack.length > 0) {
return this._fieldDefStack[this._fieldDefStack.length - 1];
}
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/validation/rules/OverlappingFieldsCanBeMerged.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ type ConflictReason = [ string, ConflictReasonMessage ];
// Reason is a string, or a nested list of conflicts.
type ConflictReasonMessage = string | Array<ConflictReason>;
// 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<NodeAndDef> };

Expand Down
2 changes: 1 addition & 1 deletion src/validation/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export class ValidationContext {
return this._typeInfo.getInputType();
}

getFieldDef(): ?GraphQLField {
getFieldDef(): ?GraphQLField<*, *> {
return this._typeInfo.getFieldDef();
}

Expand Down

0 comments on commit 3450c46

Please sign in to comment.