When `instanceof` is acting up

205 Views Asked by At

I recently filed an issue on GitHub but the project doesn’t seem to be very active so I am unsure if it will reach many fellow developers.

Here is the link to the issue: https://github.com/Urigo/graphql-modules/issues/2337.

To give a bit of context, I am currently working on a GraphQL API written in TypeScript and using the graphql-modules library calling instanceof within one of its functions.

Here is the code of the said function (altered to add some logging):

function isScalarResolver(obj) {
    console.log('obj:', obj, '\nisScalarResolver(obj):', obj instanceof GraphQLScalarType, '\n');
    return obj instanceof GraphQLScalarType;
}

After running pnpm run test, here is the output displayed in the terminal:

obj: { now: [Function: now] }
isScalarResolver(obj): false

obj: GraphQLScalarType {
  name: 'DateTime',
  description: 'DateTime scalar type',
  specifiedByURL: undefined,
  serialize: [Function: serialize],
  parseValue: [Function: parseValue],
  parseLiteral: [Function: parseLiteral],
  extensions: [Object: null prototype] {},
  astNode: undefined,
  extensionASTNodes: []
}
isScalarResolver(obj): false

It does appear to me that obj is an instance of GraphQLScalarType so obj instanceof GraphQLScalarType should return true (which is actually the case when running pnpm run dev).

For those who would want to look into the issue, there is a reproduction on StackBlitz: https://stackblitz.com/github/devatina11yb/graphql-modules.

Reproduction steps:

  1. Open the code on StackBlitz.
  2. Run the command open /home/projects/qgnikzovb.github/node_modules/.pnpm/[email protected][email protected]/node_modules/graphql-modules/index.mjs in the terminal (it will open the file in the editor).
  3. Alter the function isScalarResolver at line 1859 by adding console.log('obj:', obj, '\nisScalarResolver(obj):', obj instanceof GraphQLScalarType, '\n');.
  4. Run the command pnpm run test in the terminal.
  5. You will get the output mentioned above.

You can also confirm that the code does run without errors by running the command pnpm run dev in the terminal.

Here is the output after running pnpm run dev:

obj: { now: [Function: now] }
isScalarResolver(obj): false

obj: GraphQLScalarType {
  name: 'DateTime',
  description: 'DateTime scalar type',
  specifiedByURL: undefined,
  serialize: [Function: serialize],
  parseValue: [Function: parseValue],
  parseLiteral: [Function: parseLiteral],
  extensions: [Object: null prototype] {},
  astNode: undefined,
  extensionASTNodes: []
}
isScalarResolver(obj): true

obj: {
  now: [Function: now] { [Symbol(metadata)]: { moduleId: 'scalars' } }
}
isScalarResolver(obj): false

obj: GraphQLScalarType {
  name: 'DateTime',
  description: 'DateTime scalar type',
  specifiedByURL: undefined,
  serialize: [Function: serialize] { [Symbol(metadata)]: { moduleId: 'scalars' } },
  parseValue: [Function: parseValue] { [Symbol(metadata)]: { moduleId: 'scalars' } },
  parseLiteral: [Function: parseLiteral] {
    [Symbol(metadata)]: { moduleId: 'scalars' }
  },
  extensions: [Object: null prototype] {},
  astNode: undefined,
  extensionASTNodes: []
}
isScalarResolver(obj): true

EDIT 1

After further investigations with the debugger, it appears that GraphQLScalarType classes are loaded from different files: node_modules/.pnpm/[email protected]/node_modules/graphql/type/definition.js and node_modules/.pnpm/[email protected]/node_modules/graphql/type/definition.mjs causing instanceof to return false.

This is actually known as the dual package hazard having both CJS and ESM packages loaded at the same time. So graphql-js is the source of this issue and it has already been reported multiple times on GitHub.

1

There are 1 best solutions below

1
On

This usually happens when you have the same package installed multiple times (at different paths). Make sure that your code, and all of your dependencies, import the exact same module from the same location.

One reason might be that you have multiple dependencies installed that depend on different version of the same package (graphql-js in this case). Use a lockfile to ensure there is only a single version used.