Repository: graphql/graphql-js
Pull request #3279 (2021-09-29 13:04:14)

Make 'extensions' non-optional in schema types


Patch:
diff --git a/src/jsutils/toObjMap.ts b/src/jsutils/toObjMap.ts
index 63d6c27e..6fe352db 100644
--- a/src/jsutils/toObjMap.ts
+++ b/src/jsutils/toObjMap.ts
@@ -1,13 +1,13 @@
-import type {
-  ObjMap,
-  ObjMapLike,
-  ReadOnlyObjMap,
-  ReadOnlyObjMapLike,
-} from './ObjMap';
+import type { Maybe } from './Maybe';
+import type { ReadOnlyObjMap, ReadOnlyObjMapLike } from './ObjMap';
+
+export function toObjMap<T>(
+  obj: Maybe<ReadOnlyObjMapLike<T>>,
+): ReadOnlyObjMap<T> {
+  if (obj == null) {
+    return Object.create(null);
+  }
 
-export function toObjMap<T>(obj: ObjMapLike<T>): ObjMap<T>;
-export function toObjMap<T>(obj: ReadOnlyObjMapLike<T>): ReadOnlyObjMap<T>;
-export function toObjMap<T>(obj: ObjMapLike<T> | ReadOnlyObjMapLike<T>) {
   if (Object.getPrototypeOf(obj) === null) {
     return obj;
   }
diff --git a/src/type/definition.ts b/src/type/definition.ts
index 5372bbd4..ab3dfcfc 100644
--- a/src/type/definition.ts
+++ b/src/type/definition.ts
@@ -586,7 +586,7 @@ export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
   serialize: GraphQLScalarSerializer<TExternal>;
   parseValue: GraphQLScalarValueParser<TInternal>;
   parseLiteral: GraphQLScalarLiteralParser<TInternal>;
-  extensions: Maybe<Readonly<GraphQLScalarTypeExtensions>>;
+  extensions: Readonly<GraphQLScalarTypeExtensions>;
   astNode: Maybe<ScalarTypeDefinitionNode>;
   extensionASTNodes: ReadonlyArray<ScalarTypeExtensionNode>;
 
@@ -604,7 +604,7 @@ export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
     this.parseLiteral =
       config.parseLiteral ??
       ((node, variables) => parseValue(valueFromASTUntyped(node, variables)));
-    this.extensions = config.extensions && toObjMap(config.extensions);
+    this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
@@ -691,7 +691,7 @@ interface GraphQLScalarTypeNormalizedConfig<TInternal, TExternal>
   serialize: GraphQLScalarSerializer<TExternal>;
   parseValue: GraphQLScalarValueParser<TInternal>;
   parseLiteral: GraphQLScalarLiteralParser<TInternal>;
-  extensions: Maybe<Readonly<GraphQLScalarTypeExtensions>>;
+  extensions: Readonly<GraphQLScalarTypeExtensions>;
   extensionASTNodes: ReadonlyArray<ScalarTypeExtensionNode>;
 }
 
@@ -755,7 +755,7 @@ export class GraphQLObjectType<TSource = any, TContext = any> {
   name: string;
   description: Maybe<string>;
   isTypeOf: Maybe<GraphQLIsTypeOfFn<TSource, TContext>>;
-  extensions: Maybe<Readonly<GraphQLObjectTypeExtensions<TSource, TContext>>>;
+  extensions: Readonly<GraphQLObjectTypeExtensions<TSource, TContext>>;
   astNode: Maybe<ObjectTypeDefinitionNode>;
   extensionASTNodes: ReadonlyArray<ObjectTypeExtensionNode>;
 
@@ -766,7 +766,7 @@ export class GraphQLObjectType<TSource = any, TContext = any> {
     this.name = config.name;
     this.description = config.description;
     this.isTypeOf = config.isTypeOf;
-    this.extensions = config.extensions && toObjMap(config.extensions);
+    this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
@@ -870,7 +870,7 @@ function defineFieldMap<TSource, TContext>(
       resolve: fieldConfig.resolve,
       subscribe: fieldConfig.subscribe,
       deprecationReason: fieldConfig.deprecationReason,
-      extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions),
+      extensions: toObjMap(fieldConfig.extensions),
       astNode: fieldConfig.astNode,
     };
   });
@@ -885,7 +885,7 @@ export function defineArguments(
     type: argConfig.type,
     defaultValue: argConfig.defaultValue,
     deprecationReason: argConfig.deprecationReason,
-    extensions: argConfig.extensions && toObjMap(argConfig.extensions),
+    extensions: toObjMap(argConfig.extensions),
     astNode: argConfig.astNode,
   }));
 }
@@ -944,7 +944,7 @@ interface GraphQLObjectTypeNormalizedConfig<TSource, TContext>
   extends GraphQLObjectTypeConfig<any, any> {
   interfaces: ReadonlyArray<GraphQLInterfaceType>;
   fields: GraphQLFieldConfigMap<any, any>;
-  extensions: Maybe<Readonly<GraphQLObjectTypeExtensions<TSource, TContext>>>;
+  extensions: Readonly<GraphQLObjectTypeExtensions<TSource, TContext>>;
   extensionASTNodes: ReadonlyArray<ObjectTypeExtensionNode>;
 }
 
@@ -1063,7 +1063,7 @@ export interface GraphQLField<
   resolve?: GraphQLFieldResolver<TSource, TContext, TArgs>;
   subscribe?: GraphQLFieldResolver<TSource, TContext, TArgs>;
   deprecationReason: Maybe<string>;
-  extensions: Maybe<Readonly<GraphQLFieldExtensions<TSource, TContext, TArgs>>>;
+  extensions: Readonly<GraphQLFieldExtensions<TSource, TContext, TArgs>>;
   astNode: Maybe<FieldDefinitionNode>;
 }
 
@@ -1073,7 +1073,7 @@ export interface GraphQLArgument {
   type: GraphQLInputType;
   defaultValue: unknown;
   deprecationReason: Maybe<string>;
-  extensions: Maybe<Readonly<GraphQLArgumentExtensions>>;
+  extensions: Readonly<GraphQLArgumentExtensions>;
   astNode: Maybe<InputValueDefinitionNode>;
 }
 
@@ -1121,7 +1121,7 @@ export class GraphQLInterfaceType {
   name: string;
   description: Maybe<string>;
   resolveType: Maybe<GraphQLTypeResolver<any, any>>;
-  extensions: Maybe<Readonly<GraphQLInterfaceTypeExtensions>>;
+  extensions: Readonly<GraphQLInterfaceTypeExtensions>;
   astNode: Maybe<InterfaceTypeDefinitionNode>;
   extensionASTNodes: ReadonlyArray<InterfaceTypeExtensionNode>;
 
@@ -1132,7 +1132,7 @@ export class GraphQLInterfaceType {
     this.name = config.name;
     this.description = config.description;
     this.resolveType = config.resolveType;
-    this.extensions = config.extensions && toObjMap(config.extensions);
+    this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
@@ -1206,7 +1206,7 @@ export interface GraphQLInterfaceTypeNormalizedConfig
   extends GraphQLInterfaceTypeConfig<any, any> {
   interfaces: ReadonlyArray<GraphQLInterfaceType>;
   fields: GraphQLFieldConfigMap<any, any>;
-  extensions: Maybe<Readonly<GraphQLInterfaceTypeExtensions>>;
+  extensions: Readonly<GraphQLInterfaceTypeExtensions>;
   extensionASTNodes: ReadonlyArray<InterfaceTypeExtensionNode>;
 }
 
@@ -1251,7 +1251,7 @@ export class GraphQLUnionType {
   name: string;
   description: Maybe<string>;
   resolveType: Maybe<GraphQLTypeResolver<any, any>>;
-  extensions: Maybe<Readonly<GraphQLUnionTypeExtensions>>;
+  extensions: Readonly<GraphQLUnionTypeExtensions>;
   astNode: Maybe<UnionTypeDefinitionNode>;
   extensionASTNodes: ReadonlyArray<UnionTypeExtensionNode>;
 
@@ -1261,7 +1261,7 @@ export class GraphQLUnionType {
     this.name = config.name;
     this.description = config.description;
     this.resolveType = config.resolveType;
-    this.extensions = config.extensions && toObjMap(config.extensions);
+    this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
@@ -1335,7 +1335,7 @@ export interface GraphQLUnionTypeConfig<TSource, TContext> {
 interface GraphQLUnionTypeNormalizedConfig
   extends GraphQLUnionTypeConfig<any, any> {
   types: ReadonlyArray<GraphQLObjectType>;
-  extensions: Maybe<Readonly<GraphQLUnionTypeExtensions>>;
+  extensions: Readonly<GraphQLUnionTypeExtensions>;
   extensionASTNodes: ReadonlyArray<UnionTypeExtensionNode>;
 }
 
@@ -1378,7 +1378,7 @@ export interface GraphQLEnumTypeExtensions {
 export class GraphQLEnumType /* <T> */ {
   name: string;
   description: Maybe<string>;
-  extensions: Maybe<Readonly<GraphQLEnumTypeExtensions>>;
+  extensions: Readonly<GraphQLEnumTypeExtensions>;
   astNode: Maybe<EnumTypeDefinitionNode>;
   extensionASTNodes: ReadonlyArray<EnumTypeExtensionNode>;
 
@@ -1389,7 +1389,7 @@ export class GraphQLEnumType /* <T> */ {
   constructor(config: Readonly<GraphQLEnumTypeConfig /* <T> */>) {
     this.name = config.name;
     this.description = config.description;
-    this.extensions = config.extensions && toObjMap(config.extensions);
+    this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
@@ -1530,7 +1530,7 @@ function defineEnumValues(
       description: valueConfig.description,
       value: valueConfig.value !== undefined ? valueConfig.value : valueName,
       deprecationReason: valueConfig.deprecationReason,
-      extensions: valueConfig.extensions && toObjMap(valueConfig.extensions),
+      extensions: toObjMap(valueConfig.extensions),
       astNode: valueConfig.astNode,
     };
   });
@@ -1546,7 +1546,7 @@ export interface GraphQLEnumTypeConfig {
 }
 
 interface GraphQLEnumTypeNormalizedConfig extends GraphQLEnumTypeConfig {
-  extensions: Maybe<Readonly<GraphQLEnumTypeExtensions>>;
+  extensions: Readonly<GraphQLEnumTypeExtensions>;
   extensionASTNodes: ReadonlyArray<EnumTypeExtensionNode>;
 }
 
@@ -1579,7 +1579,7 @@ export interface GraphQLEnumValue {
   description: Maybe<string>;
   value: any /* T */;
   deprecationReason: Maybe<string>;
-  extensions: Maybe<Readonly<GraphQLEnumValueExtensions>>;
+  extensions: Readonly<GraphQLEnumValueExtensions>;
   astNode: Maybe<EnumValueDefinitionNode>;
 }
 
@@ -1620,7 +1620,7 @@ export interface GraphQLInputObjectTypeExtensions {
 export class GraphQLInputObjectType {
   name: string;
   description: Maybe<string>;
-  extensions: Maybe<Readonly<GraphQLInputObjectTypeExtensions>>;
+  extensions: Readonly<GraphQLInputObjectTypeExtensions>;
   astNode: Maybe<InputObjectTypeDefinitionNode>;
   extensionASTNodes: ReadonlyArray<InputObjectTypeExtensionNode>;
 
@@ -1629,7 +1629,7 @@ export class GraphQLInputObjectType {
   constructor(config: Readonly<GraphQLInputObjectTypeConfig>) {
     this.name = config.name;
     this.description = config.description;
-    this.extensions = config.extensions && toObjMap(config.extensions);
+    this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
@@ -1697,7 +1697,7 @@ function defineInputFieldMap(
       type: fieldConfig.type,
       defaultValue: fieldConfig.defaultValue,
       deprecationReason: fieldConfig.deprecationReason,
-      extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions),
+      extensions: toObjMap(fieldConfig.extensions),
       astNode: fieldConfig.astNode,
     };
   });
@@ -1715,7 +1715,7 @@ export interface GraphQLInputObjectTypeConfig {
 interface GraphQLInputObjectTypeNormalizedConfig
   extends GraphQLInputObjectTypeConfig {
   fields: GraphQLInputFieldConfigMap;
-  extensions: Maybe<Readonly<GraphQLInputObjectTypeExtensions>>;
+  extensions: Readonly<GraphQLInputObjectTypeExtensions>;
   extensionASTNodes: ReadonlyArray<InputObjectTypeExtensionNode>;
 }
 
@@ -1749,7 +1749,7 @@ export interface GraphQLInputField {
   type: GraphQLInputType;
   defaultValue: unknown;
   deprecationReason: Maybe<string>;
-  extensions: Maybe<Readonly<GraphQLInputFieldExtensions>>;
+  extensions: Readonly<GraphQLInputFieldExtensions>;
   astNode: Maybe<InputValueDefinitionNode>;
 }
 
diff --git a/src/type/directives.ts b/src/type/directives.ts
index c2678a6a..0179c729 100644
--- a/src/type/directives.ts
+++ b/src/type/directives.ts
@@ -59,7 +59,7 @@ export class GraphQLDirective {
   locations: ReadonlyArray<DirectiveLocationEnum>;
   args: ReadonlyArray<GraphQLArgument>;
   isRepeatable: boolean;
-  extensions: Maybe<Readonly<GraphQLDirectiveExtensions>>;
+  extensions: Readonly<GraphQLDirectiveExtensions>;
   astNode: Maybe<DirectiveDefinitionNode>;
 
   constructor(config: Readonly<GraphQLDirectiveConfig>) {
@@ -67,7 +67,7 @@ export class GraphQLDirective {
     this.description = config.description;
     this.locations = config.locations;
     this.isRepeatable = config.isRepeatable ?? false;
-    this.extensions = config.extensions && toObjMap(config.extensions);
+    this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
 
     devAssert(config.name, 'Directive must be named.');
@@ -123,7 +123,7 @@ export interface GraphQLDirectiveConfig {
 interface GraphQLDirectiveNormalizedConfig extends GraphQLDirectiveConfig {
   args: GraphQLFieldConfigArgumentMap;
   isRepeatable: boolean;
-  extensions: Maybe<Readonly<GraphQLDirectiveExtensions>>;
+  extensions: Readonly<GraphQLDirectiveExtensions>;
 }
 
 /**
diff --git a/src/type/introspection.ts b/src/type/introspection.ts
index d7c555f4..2e50bb5f 100644
--- a/src/type/introspection.ts
+++ b/src/type/introspection.ts
@@ -502,7 +502,7 @@ export const SchemaMetaFieldDef: GraphQLField<unknown, unknown> = {
   args: [],
   resolve: (_source, _args, _context, { schema }) => schema,
   deprecationReason: undefined,
-  extensions: undefined,
+  extensions: Object.create(null),
   astNode: undefined,
 };
 
@@ -517,13 +517,13 @@ export const TypeMetaFieldDef: GraphQLField<unknown, unknown> = {
       type: new GraphQLNonNull(GraphQLString),
       defaultValue: undefined,
       deprecationReason: undefined,
-      extensions: undefined,
+      extensions: Object.create(null),
       astNode: undefined,
     },
   ],
   resolve: (_source, { name }, _context, { schema }) => schema.getType(name),
   deprecationReason: undefined,
-  extensions: undefined,
+  extensions: Object.create(null),
   astNode: undefined,
 };
 
@@ -534,7 +534,7 @@ export const TypeNameMetaFieldDef: GraphQLField<unknown, unknown> = {
   args: [],
   resolve: (_source, _args, _context, { parentType }) => parentType.name,
   deprecationReason: undefined,
-  extensions: undefined,
+  extensions: Object.create(null),
   astNode: undefined,
 };
 
diff --git a/src/type/schema.ts b/src/type/schema.ts
index 9ed4c41b..869327c3 100644
--- a/src/type/schema.ts
+++ b/src/type/schema.ts
@@ -128,7 +128,7 @@ export interface GraphQLSchemaExtensions {
  */
 export class GraphQLSchema {
   description: Maybe<string>;
-  extensions: Maybe<Readonly<GraphQLSchemaExtensions>>;
+  extensions: Readonly<GraphQLSchemaExtensions>;
   astNode: Maybe<SchemaDefinitionNode>;
   extensionASTNodes: ReadonlyArray<SchemaExtensionNode>;
 
@@ -164,7 +164,7 @@ export class GraphQLSchema {
     );
 
     this.description = config.description;
-    this.extensions = config.extensions && toObjMap(config.extensions);
+    this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
@@ -386,7 +386,7 @@ export interface GraphQLSchemaNormalizedConfig extends GraphQLSchemaConfig {
   description: Maybe<string>;
   types: ReadonlyArray<GraphQLNamedType>;
   directives: ReadonlyArray<GraphQLDirective>;
-  extensions: Maybe<Readonly<GraphQLSchemaExtensions>>;
+  extensions: Readonly<GraphQLSchemaExtensions>;
   extensionASTNodes: ReadonlyArray<SchemaExtensionNode>;
   assumeValid: boolean;
 }
diff --git a/src/utilities/buildASTSchema.ts b/src/utilities/buildASTSchema.ts
index 9d76b55a..9b69e4dd 100644
--- a/src/utilities/buildASTSchema.ts
+++ b/src/utilities/buildASTSchema.ts
@@ -50,7 +50,7 @@ export function buildASTSchema(
     description: undefined,
     types: [],
     directives: [],
-    extensions: undefined,
+    extensions: Object.create(null),
     extensionASTNodes: [],
     assumeValid: false,
   };
diff --git a/src/utilities/extendSchema.ts b/src/utilities/extendSchema.ts
index 7b82e2ce..6a96ddb3 100644
--- a/src/utilities/extendSchema.ts
+++ b/src/utilities/extendSchema.ts
@@ -206,7 +206,7 @@ export function extendSchemaImpl(
       ...schemaConfig.directives.map(replaceDirective),
       ...directiveDefs.map(buildDirective),
     ],
-    extensions: undefined,
+    extensions: Object.create(null),
     astNode: schemaDef ?? schemaConfig.astNode,
     extensionASTNodes: schemaConfig.extensionASTNodes.concat(schemaExtensions),
     assumeValid: options?.assumeValid ?? false,


Test patch:
diff --git a/integrationTests/ts/index.ts b/integrationTests/ts/index.ts
index 41bbba2e..ccc378ab 100644
--- a/integrationTests/ts/index.ts
+++ b/integrationTests/ts/index.ts
@@ -61,12 +61,12 @@ const schema: GraphQLSchema = new GraphQLSchema({
 
 function checkExtensionTypes(_test: SomeExtension | null | undefined) {}
 
-checkExtensionTypes(queryType?.extensions?.someObjectExtension);
+checkExtensionTypes(queryType.extensions.someObjectExtension);
 
-const sayHiField = queryType?.getFields()?.sayHi;
-checkExtensionTypes(sayHiField?.extensions?.someFieldExtension);
+const sayHiField = queryType.getFields().sayHi;
+checkExtensionTypes(sayHiField.extensions.someFieldExtension);
 
-checkExtensionTypes(sayHiField?.args?.[0]?.extensions?.someArgumentExtension);
+checkExtensionTypes(sayHiField.args[0].extensions.someArgumentExtension);
 
 const result: ExecutionResult = graphqlSync({
   schema,
diff --git a/src/jsutils/__tests__/toObjMap-test.ts b/src/jsutils/__tests__/toObjMap-test.ts
index 8086193d..f9136b87 100644
--- a/src/jsutils/__tests__/toObjMap-test.ts
+++ b/src/jsutils/__tests__/toObjMap-test.ts
@@ -8,6 +8,18 @@ import { toObjMap } from '../toObjMap';
 const __proto__ = '__proto__';
 
 describe('toObjMap', () => {
+  it('convert undefined to ObjMap', () => {
+    const result = toObjMap(undefined);
+    expect(result).to.deep.equal({});
+    expect(Object.getPrototypeOf(result)).to.equal(null);
+  });
+
+  it('convert null to ObjMap', () => {
+    const result = toObjMap(null);
+    expect(result).to.deep.equal({});
+    expect(Object.getPrototypeOf(result)).to.equal(null);
+  });
+
   it('convert empty object to ObjMap', () => {
     const result = toObjMap({});
     expect(result).to.deep.equal({});
diff --git a/src/type/__tests__/definition-test.ts b/src/type/__tests__/definition-test.ts
index 7011937c..0b73a021 100644
--- a/src/type/__tests__/definition-test.ts
+++ b/src/type/__tests__/definition-test.ts
@@ -250,7 +250,7 @@ describe('Type System: Objects', () => {
         resolve: undefined,
         subscribe: undefined,
         deprecationReason: undefined,
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
     });
@@ -280,14 +280,14 @@ describe('Type System: Objects', () => {
             type: ScalarType,
             defaultValue: undefined,
             deprecationReason: undefined,
-            extensions: undefined,
+            extensions: {},
             astNode: undefined,
           },
         ],
         resolve: undefined,
         subscribe: undefined,
         deprecationReason: undefined,
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
     });
@@ -628,7 +628,7 @@ describe('Type System: Enums', () => {
         description: undefined,
         value: null,
         deprecationReason: undefined,
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
       {
@@ -636,7 +636,7 @@ describe('Type System: Enums', () => {
         description: undefined,
         value: NaN,
         deprecationReason: undefined,
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
       {
@@ -644,7 +644,7 @@ describe('Type System: Enums', () => {
         description: undefined,
         value: 'NO_CUSTOM_VALUE',
         deprecationReason: undefined,
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
     ]);
@@ -735,7 +735,7 @@ describe('Type System: Input Objects', () => {
           type: ScalarType,
           defaultValue: undefined,
           deprecationReason: undefined,
-          extensions: undefined,
+          extensions: {},
           astNode: undefined,
         },
       });
@@ -754,7 +754,7 @@ describe('Type System: Input Objects', () => {
           description: undefined,
           type: ScalarType,
           defaultValue: undefined,
-          extensions: undefined,
+          extensions: {},
           deprecationReason: undefined,
           astNode: undefined,
         },
diff --git a/src/type/__tests__/directive-test.ts b/src/type/__tests__/directive-test.ts
index 19249b3b..3b481bd1 100644
--- a/src/type/__tests__/directive-test.ts
+++ b/src/type/__tests__/directive-test.ts
@@ -38,7 +38,7 @@ describe('Type System: Directive', () => {
           type: GraphQLString,
           defaultValue: undefined,
           deprecationReason: undefined,
-          extensions: undefined,
+          extensions: {},
           astNode: undefined,
         },
         {
@@ -47,7 +47,7 @@ describe('Type System: Directive', () => {
           type: GraphQLInt,
           defaultValue: undefined,
           deprecationReason: undefined,
-          extensions: undefined,
+          extensions: {},
           astNode: undefined,
         },
       ],
diff --git a/src/type/__tests__/enumType-test.ts b/src/type/__tests__/enumType-test.ts
index 301eb138..2c348e63 100644
--- a/src/type/__tests__/enumType-test.ts
+++ b/src/type/__tests__/enumType-test.ts
@@ -348,7 +348,7 @@ describe('Type System: Enum Values', () => {
         description: undefined,
         value: Complex1,
         deprecationReason: undefined,
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
       {
@@ -356,7 +356,7 @@ describe('Type System: Enum Values', () => {
         description: undefined,
         value: Complex2,
         deprecationReason: undefined,
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
     ]);
diff --git a/src/type/__tests__/extensions-test.ts b/src/type/__tests__/extensions-test.ts
index 93cdedcb..e1c70df5 100644
--- a/src/type/__tests__/extensions-test.ts
+++ b/src/type/__tests__/extensions-test.ts
@@ -26,10 +26,10 @@ describe('Type System: Extensions', () => {
   describe('GraphQLScalarType', () => {
     it('without extensions', () => {
       const someScalar = new GraphQLScalarType({ name: 'SomeScalar' });
-      expect(someScalar.extensions).to.equal(undefined);
+      expect(someScalar.extensions).to.deep.equal({});
 
       const config = someScalar.toConfig();
-      expect(config.extensions).to.equal(undefined);
+      expect(config.extensions).to.deep.equal({});
     });
 
     it('with extensions', () => {
@@ -62,19 +62,19 @@ describe('Type System: Extensions', () => {
         },
       });
 
-      expect(someObject.extensions).to.equal(undefined);
+      expect(someObject.extensions).to.deep.equal({});
       const someField = someObject.getFields().someField;
-      expect(someField.extensions).to.equal(undefined);
+      expect(someField.extensions).to.deep.equal({});
       const someArg = someField.args[0];
-      expect(someArg.extensions).to.equal(undefined);
+      expect(someArg.extensions).to.deep.equal({});
 
       const config = someObject.toConfig();
-      expect(config.extensions).to.equal(undefined);
+      expect(config.extensions).to.deep.equal({});
       const someFieldConfig = config.fields.someField;
-      expect(someFieldConfig.extensions).to.equal(undefined);
+      expect(someFieldConfig.extensions).to.deep.equal({});
       invariant(someFieldConfig.args);
       const someArgConfig = someFieldConfig.args.someArg;
-      expect(someArgConfig.extensions).to.equal(undefined);
+      expect(someArgConfig.extensions).to.deep.equal({});
     });
 
     it('with extensions', () => {
@@ -131,19 +131,19 @@ describe('Type System: Extensions', () => {
         },
       });
 
-      expect(someInterface.extensions).to.equal(undefined);
+      expect(someInterface.extensions).to.deep.equal({});
       const someField = someInterface.getFields().someField;
-      expect(someField.extensions).to.equal(undefined);
+      expect(someField.extensions).to.deep.equal({});
       const someArg = someField.args[0];
-      expect(someArg.extensions).to.equal(undefined);
+      expect(someArg.extensions).to.deep.equal({});
 
       const config = someInterface.toConfig();
-      expect(config.extensions).to.equal(undefined);
+      expect(config.extensions).to.deep.equal({});
       const someFieldConfig = config.fields.someField;
-      expect(someFieldConfig.extensions).to.equal(undefined);
+      expect(someFieldConfig.extensions).to.deep.equal({});
       invariant(someFieldConfig.args);
       const someArgConfig = someFieldConfig.args.someArg;
-      expect(someArgConfig.extensions).to.equal(undefined);
+      expect(someArgConfig.extensions).to.deep.equal({});
     });
 
     it('with extensions', () => {
@@ -193,10 +193,10 @@ describe('Type System: Extensions', () => {
         types: [],
       });
 
-      expect(someUnion.extensions).to.equal(undefined);
+      expect(someUnion.extensions).to.deep.equal({});
 
       const config = someUnion.toConfig();
-      expect(config.extensions).to.equal(undefined);
+      expect(config.extensions).to.deep.equal({});
     });
 
     it('with extensions', () => {
@@ -224,14 +224,14 @@ describe('Type System: Extensions', () => {
         },
       });
 
-      expect(someEnum.extensions).to.equal(undefined);
+      expect(someEnum.extensions).to.deep.equal({});
       const someValue = someEnum.getValues()[0];
-      expect(someValue.extensions).to.equal(undefined);
+      expect(someValue.extensions).to.deep.equal({});
 
       const config = someEnum.toConfig();
-      expect(config.extensions).to.equal(undefined);
+      expect(config.extensions).to.deep.equal({});
       const someValueConfig = config.values.SOME_VALUE;
-      expect(someValueConfig.extensions).to.equal(undefined);
+      expect(someValueConfig.extensions).to.deep.equal({});
     });
 
     it('with extensions', () => {
@@ -270,14 +270,14 @@ describe('Type System: Extensions', () => {
         },
       });
 
-      expect(someInputObject.extensions).to.equal(undefined);
+      expect(someInputObject.extensions).to.deep.equal({});
       const someInputField = someInputObject.getFields().someInputField;
-      expect(someInputField.extensions).to.equal(undefined);
+      expect(someInputField.extensions).to.deep.equal({});
 
       const config = someInputObject.toConfig();
-      expect(config.extensions).to.equal(undefined);
+      expect(config.extensions).to.deep.equal({});
       const someInputFieldConfig = config.fields.someInputField;
-      expect(someInputFieldConfig.extensions).to.equal(undefined);
+      expect(someInputFieldConfig.extensions).to.deep.equal({});
     });
 
     it('with extensions', () => {
@@ -328,14 +328,14 @@ describe('Type System: Extensions', () => {
         locations: [],
       });
 
-      expect(someDirective.extensions).to.equal(undefined);
+      expect(someDirective.extensions).to.deep.equal({});
       const someArg = someDirective.args[0];
-      expect(someArg.extensions).to.equal(undefined);
+      expect(someArg.extensions).to.deep.equal({});
 
       const config = someDirective.toConfig();
-      expect(config.extensions).to.equal(undefined);
+      expect(config.extensions).to.deep.equal({});
       const someArgConfig = config.args.someArg;
-      expect(someArgConfig.extensions).to.equal(undefined);
+      expect(someArgConfig.extensions).to.deep.equal({});
     });
 
     it('with extensions', () => {
@@ -371,10 +371,10 @@ describe('Type System: Extensions', () => {
     it('without extensions', () => {
       const schema = new GraphQLSchema({});
 
-      expect(schema.extensions).to.equal(undefined);
+      expect(schema.extensions).to.deep.equal({});
 
       const config = schema.toConfig();
-      expect(config.extensions).to.equal(undefined);
+      expect(config.extensions).to.deep.equal({});
     });
 
     it('with extensions', () => {
diff --git a/src/type/__tests__/predicate-test.ts b/src/type/__tests__/predicate-test.ts
index 94e152e1..0323be43 100644
--- a/src/type/__tests__/predicate-test.ts
+++ b/src/type/__tests__/predicate-test.ts
@@ -573,7 +573,7 @@ describe('Type predicates', () => {
         description: undefined,
         defaultValue: config.defaultValue,
         deprecationReason: null,
-        extensions: undefined,
+        extensions: Object.create(null),
         astNode: undefined,
       };
     }
@@ -621,7 +621,7 @@ describe('Type predicates', () => {
         description: undefined,
         defaultValue: config.defaultValue,
         deprecationReason: null,
-        extensions: undefined,
+        extensions: Object.create(null),
         astNode: undefined,
       };
     }
diff --git a/src/utilities/__tests__/buildClientSchema-test.ts b/src/utilities/__tests__/buildClientSchema-test.ts
index d65f69b5..dc705b8a 100644
--- a/src/utilities/__tests__/buildClientSchema-test.ts
+++ b/src/utilities/__tests__/buildClientSchema-test.ts
@@ -385,7 +385,7 @@ describe('Type System: build schema from introspection', () => {
         description: 'Foods that are vegetables.',
         value: 'VEGETABLES',
         deprecationReason: null,
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
       {
@@ -393,7 +393,7 @@ describe('Type System: build schema from introspection', () => {
         description: null,
         value: 'FRUITS',
         deprecationReason: null,
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
       {
@@ -401,7 +401,7 @@ describe('Type System: build schema from introspection', () => {
         description: null,
         value: 'OILS',
         deprecationReason: 'Too fatty',
-        extensions: undefined,
+        extensions: {},
         astNode: undefined,
       },
     ]);