The entry type for a field resolver stored in a TypeResolverMap.
Declared with method syntax, which TypeScript compares bivariantly
even under strictFunctionTypes — the documented escape hatch for exactly
this case. That buys both halves at once, and both are load-bearing:
A narrowly annotated resolver assigns ((parent: IssueRow) => parent.title),
which is X6-4's goal and what the all-unknownFieldResolver rejected.
An UNANNOTATED resolver still receives these declared parameter types
contextually, so (_source, args) => rows.find((r) => r.id === args.id)
infers args as Record<string, unknown> and compiles.
Instantiating FieldResolver at never buys only (1). It makes every
parameter of an unannotated resolver infer never, so args.id becomes
Property 'id' does not exist on type 'never' — which broke apps/graphql-demo,
whose resolvers are written the ordinary unannotated way. Bivariance is the
only form that serves both authoring styles.
The entry type for a field resolver stored in a
TypeResolverMap.Declared with method syntax, which TypeScript compares bivariantly even under
strictFunctionTypes— the documented escape hatch for exactly this case. That buys both halves at once, and both are load-bearing:(parent: IssueRow) => parent.title), which is X6-4's goal and what the all-unknownFieldResolverrejected.(_source, args) => rows.find((r) => r.id === args.id)infersargsasRecord<string, unknown>and compiles.Instantiating
FieldResolveratneverbuys only (1). It makes every parameter of an unannotated resolver infernever, soargs.idbecomesProperty 'id' does not exist on type 'never'— which brokeapps/graphql-demo, whose resolvers are written the ordinary unannotated way. Bivariance is the only form that serves both authoring styles.