From 333c2486653aa226d67e7e8319b4b5e489914665 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Fri, 27 Jan 2017 12:30:17 -0800 Subject: [PATCH] Use flow %checks to reduce occurance of :any This uses a pre-release flow feature to provide predicate functions with more type checking power. It also breaks apart some functions into multiple declare function statements for cases where more specific input types result in more specific output types. --- src/execution/execute.js | 16 ++--- src/execution/values.js | 3 +- src/type/definition.js | 70 +++++++++++-------- src/type/introspection.js | 4 +- src/utilities/TypeInfo.js | 19 ++--- src/utilities/buildASTSchema.js | 12 ++-- src/utilities/buildClientSchema.js | 8 +-- src/utilities/extendSchema.js | 16 ++--- src/utilities/findBreakingChanges.js | 4 +- src/utilities/typeComparators.js | 19 ++--- src/utilities/typeFromAST.js | 39 ++++++++--- src/validation/rules/FieldsOnCorrectType.js | 5 +- .../rules/OverlappingFieldsCanBeMerged.js | 4 +- 13 files changed, 105 insertions(+), 114 deletions(-) diff --git a/src/execution/execute.js b/src/execution/execute.js index d15e3dceab..a6da446f7f 100644 --- a/src/execution/execute.js +++ b/src/execution/execute.js @@ -18,14 +18,11 @@ import { typeFromAST } from '../utilities/typeFromAST'; import * as Kind from '../language/kinds'; import { getVariableValues, getArgumentValues } from './values'; import { - GraphQLScalarType, GraphQLObjectType, - GraphQLEnumType, GraphQLList, GraphQLNonNull, - GraphQLInterfaceType, - GraphQLUnionType, - isAbstractType + isAbstractType, + isLeafType, } from '../type/definition'; import type { GraphQLType, @@ -527,8 +524,7 @@ function doesFragmentConditionMatch( return true; } if (isAbstractType(conditionalType)) { - const abstractType = ((conditionalType: any): GraphQLAbstractType); - return exeContext.schema.isPossibleType(abstractType, type); + return exeContext.schema.isPossibleType(conditionalType, type); } return false; } @@ -831,15 +827,13 @@ function completeValue( // If field type is a leaf type, Scalar or Enum, serialize to a valid value, // returning null if serialization is not possible. - if (returnType instanceof GraphQLScalarType || - returnType instanceof GraphQLEnumType) { + if (isLeafType(returnType)) { return completeLeafValue(returnType, result); } // If field type is an abstract type, Interface or Union, determine the // runtime Object type and complete for that type. - if (returnType instanceof GraphQLInterfaceType || - returnType instanceof GraphQLUnionType) { + if (isAbstractType(returnType)) { return completeAbstractValue( exeContext, returnType, diff --git a/src/execution/values.js b/src/execution/values.js index 9c0b340148..8ce519c0f4 100644 --- a/src/execution/values.js +++ b/src/execution/values.js @@ -57,7 +57,7 @@ export function getVariableValues( for (let i = 0; i < varDefNodes.length; i++) { const varDefNode = varDefNodes[i]; const varName = varDefNode.variable.name.value; - let varType = typeFromAST(schema, varDefNode.type); + const varType = typeFromAST(schema, varDefNode.type); if (!isInputType(varType)) { throw new GraphQLError( `Variable "$${varName}" expected value of type ` + @@ -65,7 +65,6 @@ export function getVariableValues( [ varDefNode.type ] ); } - varType = ((varType: any): GraphQLInputType); const value = inputs[varName]; if (isInvalid(value)) { diff --git a/src/type/definition.js b/src/type/definition.js index 1d892226d8..9fd9a459d1 100644 --- a/src/type/definition.js +++ b/src/type/definition.js @@ -72,12 +72,13 @@ export type GraphQLInputType = GraphQLList >; -export function isInputType(type: ?GraphQLType): boolean { - const namedType = getNamedType(type); +export function isInputType(type: ?GraphQLType): boolean %checks { return ( - namedType instanceof GraphQLScalarType || - namedType instanceof GraphQLEnumType || - namedType instanceof GraphQLInputObjectType + type instanceof GraphQLScalarType || + type instanceof GraphQLEnumType || + type instanceof GraphQLInputObjectType || + type instanceof GraphQLNonNull && isInputType(type.ofType) || + type instanceof GraphQLList && isInputType(type.ofType) ); } @@ -86,7 +87,7 @@ export function assertInputType(type: ?GraphQLType): GraphQLInputType { isInputType(type), `Expected ${String(type)} to be a GraphQL input type.` ); - return (type: any); + return type; } /** @@ -108,14 +109,15 @@ export type GraphQLOutputType = GraphQLList >; -export function isOutputType(type: ?GraphQLType): boolean { - const namedType = getNamedType(type); +export function isOutputType(type: ?GraphQLType): boolean %checks { return ( - namedType instanceof GraphQLScalarType || - namedType instanceof GraphQLObjectType || - namedType instanceof GraphQLInterfaceType || - namedType instanceof GraphQLUnionType || - namedType instanceof GraphQLEnumType + type instanceof GraphQLScalarType || + type instanceof GraphQLObjectType || + type instanceof GraphQLInterfaceType || + type instanceof GraphQLUnionType || + type instanceof GraphQLEnumType || + type instanceof GraphQLNonNull && isOutputType(type.ofType) || + type instanceof GraphQLList && isOutputType(type.ofType) ); } @@ -124,7 +126,7 @@ export function assertOutputType(type: ?GraphQLType): GraphQLOutputType { isOutputType(type), `Expected ${String(type)} to be a GraphQL output type.`, ); - return (type: any); + return type; } /** @@ -134,7 +136,7 @@ export type GraphQLLeafType = GraphQLScalarType | GraphQLEnumType; -export function isLeafType(type: ?GraphQLType): boolean { +export function isLeafType(type: ?GraphQLType): boolean %checks { return ( type instanceof GraphQLScalarType || type instanceof GraphQLEnumType @@ -146,7 +148,7 @@ export function assertLeafType(type: ?GraphQLType): GraphQLLeafType { isLeafType(type), `Expected ${String(type)} to be a GraphQL leaf type.`, ); - return (type: any); + return type; } /** @@ -157,7 +159,7 @@ export type GraphQLCompositeType = GraphQLInterfaceType | GraphQLUnionType; -export function isCompositeType(type: ?GraphQLType): boolean { +export function isCompositeType(type: ?GraphQLType): boolean %checks { return ( type instanceof GraphQLObjectType || type instanceof GraphQLInterfaceType || @@ -170,7 +172,7 @@ export function assertCompositeType(type: ?GraphQLType): GraphQLCompositeType { isCompositeType(type), `Expected ${String(type)} to be a GraphQL composite type.`, ); - return (type: any); + return type; } /** @@ -180,7 +182,7 @@ export type GraphQLAbstractType = GraphQLInterfaceType | GraphQLUnionType; -export function isAbstractType(type: ?GraphQLType): boolean { +export function isAbstractType(type: ?GraphQLType): boolean %checks { return ( type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType @@ -192,7 +194,7 @@ export function assertAbstractType(type: ?GraphQLType): GraphQLAbstractType { isAbstractType(type), `Expected ${String(type)} to be a GraphQL abstract type.`, ); - return (type: any); + return type; } /** @@ -224,7 +226,7 @@ export type GraphQLNamedType = GraphQLEnumType | GraphQLInputObjectType; -export function isNamedType(type: ?GraphQLType): boolean { +export function isNamedType(type: ?GraphQLType): boolean %checks { return ( type instanceof GraphQLScalarType || type instanceof GraphQLObjectType || @@ -240,18 +242,24 @@ export function assertNamedType(type: ?GraphQLType): GraphQLNamedType { isNamedType(type), `Expected ${String(type)} to be a GraphQL named type.`, ); - return (type: any); + return type; } -export function getNamedType(type: ?GraphQLType): ?GraphQLNamedType { - let unmodifiedType = type; - while ( - unmodifiedType instanceof GraphQLList || - unmodifiedType instanceof GraphQLNonNull - ) { - unmodifiedType = unmodifiedType.ofType; +/* eslint-disable no-redeclare */ +declare function getNamedType(type: void | null): void; +declare function getNamedType(type: GraphQLType): GraphQLNamedType; +export function getNamedType(type) { +/* eslint-enable no-redeclare */ + if (type) { + let unmodifiedType = type; + while ( + unmodifiedType instanceof GraphQLList || + unmodifiedType instanceof GraphQLNonNull + ) { + unmodifiedType = unmodifiedType.ofType; + } + return unmodifiedType; } - return unmodifiedType; } @@ -556,7 +564,7 @@ function isPlainObj(obj) { } // If a resolver is defined, it must be a function. -function isValidResolver(resolver: any): boolean { +function isValidResolver(resolver: mixed): boolean { return (resolver == null || typeof resolver === 'function'); } diff --git a/src/type/introspection.js b/src/type/introspection.js index 09e94c5fe4..04a295ad47 100644 --- a/src/type/introspection.js +++ b/src/type/introspection.js @@ -20,6 +20,7 @@ import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull, + isAbstractType, } from './definition'; import { GraphQLString, GraphQLBoolean } from './scalars'; import { DirectiveLocation } from './directives'; @@ -267,8 +268,7 @@ export const __Type = new GraphQLObjectType({ possibleTypes: { type: new GraphQLList(new GraphQLNonNull(__Type)), resolve(type, args, context, { schema }) { - if (type instanceof GraphQLInterfaceType || - type instanceof GraphQLUnionType) { + if (isAbstractType(type)) { return schema.getPossibleTypes(type); } } diff --git a/src/utilities/TypeInfo.js b/src/utilities/TypeInfo.js index 0965ccb44e..9805300bf9 100644 --- a/src/utilities/TypeInfo.js +++ b/src/utilities/TypeInfo.js @@ -17,7 +17,6 @@ import { getNamedType, GraphQLObjectType, GraphQLInterfaceType, - GraphQLUnionType, GraphQLInputObjectType, GraphQLEnumType, GraphQLList, @@ -120,9 +119,7 @@ export class TypeInfo { case Kind.SELECTION_SET: const namedType = getNamedType(this.getType()); this._parentTypeStack.push( - isCompositeType(namedType) ? - ((namedType: any): GraphQLCompositeType) : - undefined + isCompositeType(namedType) ? namedType : undefined ); break; case Kind.FIELD: @@ -155,17 +152,13 @@ export class TypeInfo { typeFromAST(schema, typeConditionAST) : this.getType(); this._typeStack.push( - isOutputType(outputType) ? - ((outputType: any): GraphQLOutputType) : - undefined + isOutputType(outputType) ? outputType : undefined ); break; case Kind.VARIABLE_DEFINITION: const inputType = typeFromAST(schema, node.type); this._inputTypeStack.push( - isInputType(inputType) ? - ((inputType: any): GraphQLInputType) : - undefined + isInputType(inputType) ? inputType : undefined ); break; case Kind.ARGUMENT: @@ -264,11 +257,7 @@ function getFieldDef( schema.getQueryType() === parentType) { return TypeMetaFieldDef; } - if (name === TypeNameMetaFieldDef.name && - (parentType instanceof GraphQLObjectType || - parentType instanceof GraphQLInterfaceType || - parentType instanceof GraphQLUnionType) - ) { + if (name === TypeNameMetaFieldDef.name && isCompositeType(parentType)) { return TypeNameMetaFieldDef; } if (parentType instanceof GraphQLObjectType || diff --git a/src/utilities/buildASTSchema.js b/src/utilities/buildASTSchema.js index c2cd656e9a..4095a46991 100644 --- a/src/utilities/buildASTSchema.js +++ b/src/utilities/buildASTSchema.js @@ -68,8 +68,8 @@ import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull, - isInputType, - isOutputType, + assertInputType, + assertOutputType, } from '../type/definition'; import type { @@ -299,15 +299,11 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema { } function produceInputType(typeNode: TypeNode): GraphQLInputType { - const type = produceType(typeNode); - invariant(isInputType(type), 'Expected Input type.'); - return (type: any); + return assertInputType(produceType(typeNode)); } function produceOutputType(typeNode: TypeNode): GraphQLOutputType { - const type = produceType(typeNode); - invariant(isOutputType(type), 'Expected Output type.'); - return (type: any); + return assertOutputType(produceType(typeNode)); } function produceObjectType(typeNode: TypeNode): GraphQLObjectType { diff --git a/src/utilities/buildClientSchema.js b/src/utilities/buildClientSchema.js index 17d16236bd..fca78567ed 100644 --- a/src/utilities/buildClientSchema.js +++ b/src/utilities/buildClientSchema.js @@ -162,7 +162,7 @@ export function buildClientSchema( isInputType(type), 'Introspection must provide input type for arguments.' ); - return (type: any); + return type; } function getOutputType(typeRef: IntrospectionTypeRef): GraphQLOutputType { @@ -171,7 +171,7 @@ export function buildClientSchema( isOutputType(type), 'Introspection must provide output type for fields.' ); - return (type: any); + return type; } function getObjectType(typeRef: IntrospectionTypeRef): GraphQLObjectType { @@ -180,7 +180,7 @@ export function buildClientSchema( type instanceof GraphQLObjectType, 'Introspection must provide object type for possibleTypes.' ); - return (type: any); + return type; } function getInterfaceType( @@ -191,7 +191,7 @@ export function buildClientSchema( type instanceof GraphQLInterfaceType, 'Introspection must provide interface type for interfaces.' ); - return (type: any); + return type; } diff --git a/src/utilities/extendSchema.js b/src/utilities/extendSchema.js index 77c45b383a..b9d72205b6 100644 --- a/src/utilities/extendSchema.js +++ b/src/utilities/extendSchema.js @@ -28,8 +28,8 @@ import { GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType, - isInputType, - isOutputType, + assertInputType, + assertOutputType, } from '../type/definition'; import { @@ -298,15 +298,11 @@ export function extendSchema( } function getInputTypeFromAST(node: NamedTypeNode): GraphQLInputType { - const type = getTypeFromAST(node); - invariant(isInputType(type), 'Must be Input type.'); - return (type: any); + return assertInputType(getTypeFromAST(node)); } function getOutputTypeFromAST(node: NamedTypeNode): GraphQLOutputType { - const type = getTypeFromAST(node); - invariant(isOutputType(type), 'Must be Output type.'); - return (type: any); + return assertOutputType(getTypeFromAST(node)); } // Given a name, returns a type from either the existing schema or an @@ -445,10 +441,10 @@ export function extendSchema( function extendFieldType(typeDef: T): T { if (typeDef instanceof GraphQLList) { - return (new GraphQLList(extendFieldType(typeDef.ofType)): any); + return new GraphQLList(extendFieldType(typeDef.ofType)); } if (typeDef instanceof GraphQLNonNull) { - return (new GraphQLNonNull(extendFieldType(typeDef.ofType)): any); + return new GraphQLNonNull(extendFieldType(typeDef.ofType)); } return getTypeFromDef(typeDef); } diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index 337a76ade9..f065194b33 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -281,9 +281,7 @@ export function findFieldsThatChangedType( // Check if the field's type has changed in the new schema. const oldFieldType = getNamedType(oldTypeFieldsDef[fieldName].type); const newFieldType = getNamedType(newTypeFieldsDef[fieldName].type); - if (oldFieldType && - newFieldType && - oldFieldType.name !== newFieldType.name) { + if (oldFieldType.name !== newFieldType.name) { breakingFieldChanges.push({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: `${typeName}.${fieldName} changed type from ` + diff --git a/src/utilities/typeComparators.js b/src/utilities/typeComparators.js index 1819080048..330b3c4575 100644 --- a/src/utilities/typeComparators.js +++ b/src/utilities/typeComparators.js @@ -11,15 +11,12 @@ import { isAbstractType, GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, GraphQLList, GraphQLNonNull, } from '../type/definition'; import type { GraphQLType, - GraphQLCompositeType, - GraphQLAbstractType + GraphQLCompositeType } from '../type/definition'; import type { GraphQLSchema @@ -89,10 +86,7 @@ export function isTypeSubTypeOf( // possible object type. if (isAbstractType(superType) && maybeSubType instanceof GraphQLObjectType && - schema.isPossibleType( - ((superType: any): GraphQLAbstractType), - maybeSubType - )) { + schema.isPossibleType(superType, maybeSubType)) { return true; } @@ -122,10 +116,8 @@ export function doTypesOverlap( return true; } - if (typeA instanceof GraphQLInterfaceType || - typeA instanceof GraphQLUnionType) { - if (_typeB instanceof GraphQLInterfaceType || - _typeB instanceof GraphQLUnionType) { + if (isAbstractType(typeA)) { + if (isAbstractType(_typeB)) { // If both types are abstract, then determine if there is any intersection // between possible concrete types of each. return schema.getPossibleTypes(typeA).some( @@ -136,8 +128,7 @@ export function doTypesOverlap( return schema.isPossibleType(typeA, _typeB); } - if (_typeB instanceof GraphQLInterfaceType || - _typeB instanceof GraphQLUnionType) { + if (isAbstractType(_typeB)) { // Determine if the former type is a possible concrete type of the latter. return schema.isPossibleType(_typeB, typeA); } diff --git a/src/utilities/typeFromAST.js b/src/utilities/typeFromAST.js index b0df5b476d..9b608e7e91 100644 --- a/src/utilities/typeFromAST.js +++ b/src/utilities/typeFromAST.js @@ -10,16 +10,39 @@ import invariant from '../jsutils/invariant'; import { NAMED_TYPE, LIST_TYPE, NON_NULL_TYPE } from '../language/kinds'; -import type { TypeNode } from '../language/ast'; +import type { + NamedTypeNode, + ListTypeNode, + NonNullTypeNode +} from '../language/ast'; import { GraphQLList, GraphQLNonNull } from '../type/definition'; -import type { GraphQLType, GraphQLNullableType } from '../type/definition'; +import type { + GraphQLNamedType, +} from '../type/definition'; import type { GraphQLSchema } from '../type/schema'; - -export function typeFromAST( +/** + * Given a Schema and an AST node describing a type, return a GraphQLType + * definition which applies to that type. For example, if provided the parsed + * AST node for `[User]`, a GraphQLList instance will be returned, containing + * the type called "User" found in the schema. If a type called "User" is not + * found in the schema, then undefined will be returned. + */ +/* eslint-disable no-redeclare */ +declare function typeFromAST( + schema: GraphQLSchema, + typeNode: NamedTypeNode +): void | GraphQLNamedType; +declare function typeFromAST( + schema: GraphQLSchema, + typeNode: ListTypeNode +): void | GraphQLList<*>; +declare function typeFromAST( schema: GraphQLSchema, - typeNode: TypeNode -): ?GraphQLType { + typeNode: NonNullTypeNode +): void | GraphQLNonNull<*>; +export function typeFromAST(schema, typeNode) { +/* eslint-enable no-redeclare */ let innerType; if (typeNode.kind === LIST_TYPE) { innerType = typeFromAST(schema, typeNode.type); @@ -27,9 +50,7 @@ export function typeFromAST( } if (typeNode.kind === NON_NULL_TYPE) { innerType = typeFromAST(schema, typeNode.type); - return innerType && new GraphQLNonNull( - ((innerType: any): GraphQLNullableType) - ); + return innerType && new GraphQLNonNull(innerType); } invariant(typeNode.kind === NAMED_TYPE, 'Must be a named type.'); return schema.getType(typeNode.name.value); diff --git a/src/validation/rules/FieldsOnCorrectType.js b/src/validation/rules/FieldsOnCorrectType.js index 9eb4faf944..4751720a83 100644 --- a/src/validation/rules/FieldsOnCorrectType.js +++ b/src/validation/rules/FieldsOnCorrectType.js @@ -18,7 +18,7 @@ import type { GraphQLOutputType } from '../../type/definition'; import { GraphQLObjectType, GraphQLInterfaceType, - GraphQLUnionType, + isAbstractType, } from '../../type/definition'; @@ -89,8 +89,7 @@ function getSuggestedTypeNames( type: GraphQLOutputType, fieldName: string ): Array { - if (type instanceof GraphQLInterfaceType || - type instanceof GraphQLUnionType) { + if (isAbstractType(type)) { const suggestedObjectTypes = []; const interfaceUsageCount = Object.create(null); schema.getPossibleTypes(type).forEach(possibleType => { diff --git a/src/validation/rules/OverlappingFieldsCanBeMerged.js b/src/validation/rules/OverlappingFieldsCanBeMerged.js index d6ebe56588..7a5faf7173 100644 --- a/src/validation/rules/OverlappingFieldsCanBeMerged.js +++ b/src/validation/rules/OverlappingFieldsCanBeMerged.js @@ -697,7 +697,7 @@ function getReferencedFieldsAndFragmentNames( return getFieldsAndFragmentNames( context, cachedFieldsAndFragmentNames, - ((fragmentType: any): GraphQLNamedType), + fragmentType, fragment.selectionSet ); } @@ -736,7 +736,7 @@ function _collectFieldsAndFragmentNames( parentType; _collectFieldsAndFragmentNames( context, - ((inlineFragmentType: any): GraphQLNamedType), + inlineFragmentType, selection.selectionSet, nodeAndDefs, fragmentNames