You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fixObjectTypeResolvers: 'smart' treats an unresolvable mapper type as an empty mapper and injects a stub for every field #446
When a *.mappers.ts mapper aliases a type whose import cannot be resolved (a TS error type), fixObjectTypeResolvers: 'smart' silently treats the mapper as having zero fields and injects a "resolver is required because … does not" stub for every field of the schema type — overwriting/adding stubs in the hand-maintained resolver file. The generated stubs return Promise<void> and break tsc.
This is not hypothetical: it fires whenever codegen runs before the mapped type's module exists — e.g. a Prisma client generated into node_modules that hasn't been generated yet on a fresh install. The result looks like data corruption of hand-written files and is easy to commit unnoticed.
Root cause
getGraphQLObjectTypeResolversToGenerate builds the mapper's property set from getNodePropertyMap, which does:
When node resolves to a TS error type (unresolvable import), getProperties() returns []. The code then cannot distinguish "mapper genuinely has no fields" from "mapper type could not be resolved", so every schema field takes the if (!typeMapperProperty) branch and gets a stub.
Minimal reproduction
// user-defined schema type `Foo { id: ID!, name: String! }`// mapper file:exporttypeFooMapper=Foo// Foo imported from a module that isn't installed / not generated yet
Standalone ts-morph proof of the misclassification:
import{Project,Node}from'ts-morph'constproject=newProject({skipAddingFilesFromTsConfig: true})constsf=project.createSourceFile('mapper.ts',`import type { Foo } from './does-not-exist'\nexport type FooMapper = Foo\n`)constalias=sf.getTypeAliasOrThrow('FooMapper')constnode=Node.isTypeReference(alias.getTypeNodeOrThrow())
? alias.getNameNode().getDefinitionNodes()[0]
: aliasconstprops=project.getTypeChecker().getTypeAtLocation(node).getProperties().map((p)=>p.getName())console.log(props)// => [] (error type → zero props → stubs injected for every field)
Suggested fix
Detect the error/unresolved type before deriving the property map and skip stub generation for that mapper, emitting a warning naming the mapper (so the real problem — the unresolved import — surfaces) instead of silently rewriting the resolver file. A type resolving to the intrinsic error/any-from-unresolved case is distinguishable via the type checker; when detected, getGraphQLObjectTypeResolversToGenerate should treat the mapper's property map as "unknown" (leave existing resolvers untouched) rather than "empty".
Happy to send a PR if you agree with the direction.
Activity
eddeee888 commentedon Jul 16, 2026
Hi @GlebYavorski ,
Thanks for the explanation. A PR sounds great! Thank you! 🙏
fix: don't stub every field when a mapper type is unresolvable (#446)
fix: don't stub every field when a mapper type is unresolvable
fix: don't stub every field when a mapper type is unresolvable
fix: don't stub every field when a mapper type is unresolvable (#455)
eddeee888 commentedon Sep 22, 2026
Oops, PR said fix in the body but a new package is not released.
Will release soon.
eddeee888 commentedon Oct 7, 2026
This is released here: https://github.com/eddeee888/graphql-code-generator-plugins/releases/tag/%40eddeee888%2Fgcg-typescript-resolver-files%400.20.0
Thanks for your patience! This took longer than I hoped