Skip to content

Tighten scalar codegen types (#2554)#3085

Open
ifeanyi-ugwu wants to merge 6 commits into
graphql-hive:masterfrom
ifeanyi-ugwu:feat/scalar-codegen-types
Open

Tighten scalar codegen types (#2554)#3085
ifeanyi-ugwu wants to merge 6 commits into
graphql-hive:masterfrom
ifeanyi-ugwu:feat/scalar-codegen-types

Conversation

@ifeanyi-ugwu

@ifeanyi-ugwu ifeanyi-ugwu commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Gives codegenScalarType a single consistent meaning across scalars — the
resolver-return (output) type — and emits string-literal unions for the enum
scalars. Generated resolver types then match what each scalar actually
serializes and accepts. Addresses #2554.

Why the resolver-return type

@graphql-codegen/typescript reads codegenScalarType as one string and applies
it to both the input and output slots of the generated Scalars map; the
extension alone cannot express input ≠ output. The resolver-return type is the
safe direction: a too-wide resolver argument type never errors, whereas a
too-narrow return type rejects code that serializes fine at runtime.

Changes

Enum scalars

  • CountryCode and Currency emit a string-literal union built from a single
    as const code list, with a matching jsonSchema.enum, instead of string.

codegenScalarType output type

  • USCurrency: stringnumber (resolvers return and receive cents as a number).
  • DateTime: widened to Date | string | number.
  • BigInt: widened to bigint | number | string.

Config generics (GraphQLScalarTypeConfig<TParsed, TSerialized>, generic since graphql v14)

  • NonNegativeFloat, NonNegativeInt: <any, any><number, number>.
  • Byte: <Buffer | string | BufferJson, Buffer><Buffer, Buffer>.
  • Currency: <CurrencyCode, CurrencyCode>.

Compatibility

Type-level only, with no runtime behavior change. Consumers relying on the
previously looser types may see new — and correct — compile errors where a value
was typed too broadly before. The changeset is minor.

CountryCode, Currency and CountryName accept only a fixed ISO set, so the
generated resolver type should be that string-literal union rather than a bare
`string`. The union and the jsonSchema `enum` are derived from a single
`as const` source list, and each scalar carries precise generics. Matching
stays case-insensitive and returns the input value unchanged.
Several scalars parse to one type but accept a wider set for serialization, so
the single codegenScalarType could only ever name one of them — and sometimes
named the wrong one: USCurrency claimed `string` though resolvers both return
and receive `number`. codegenScalarType now consistently carries the
resolver-return (output) type, with precise `<TParsed, TSerialized>` generics
so the parsed type stays recoverable from the scalar itself. Timestamp's
jsonSchema type is corrected to integer to match its numeric wire value.
…enerics

The scalars built from inline configs defaulted to `GraphQLScalarType<unknown,
unknown>`, hiding their real types. Each now declares `<string, string>` or
`<number, number>` to match what parseValue and serialize actually handle, so
the parsed and serialized types are visible from the scalar itself. Behavior is
unchanged; SE's string guard became an assertion so it narrows without a cast.
…branch

The jsonSchema.type correction (string -> integer, matching the numeric
serialized value) is already carried by fix/jsonschema-definitions, the branch
that owns jsonSchema definitions; duplicating it here would conflict on merge.
This keeps the branch scoped to codegen types and generics — the
`<Date, number>` generic and codegenScalarType are untouched.
Comment thread src/scalars/ssn/SE.ts Outdated

export const GraphQLSESSN: GraphQLScalarType = /*#__PURE__*/ new GraphQLScalarType({
export const GraphQLSESSN: GraphQLScalarType<string, string> = /*#__PURE__*/ new GraphQLScalarType<
string,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might break GraphQL v15 support. And it means a breaking change then.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, i totally missed that. i've reverted the change.
it's too trivial for a breaking change. i also compiled against v14 and v15 just to be sure

@ifeanyi-ugwu ifeanyi-ugwu changed the title Tighten scalar TypeScript and codegen types (#2554) Tighten scalar codegen types (#2554) Jul 10, 2026
`GraphQLScalarType` gained its `<TInternal, TExternal>` type parameters in
graphql-js v16. In v14 and v15 the class is non-generic. The class-level
`GraphQLScalarType<...>` annotations fail to typecheck there (`Type
'GraphQLScalarType' is not generic`) — a breaking change for consumers on the
v14/v15 peer range, which the minor changeset did not account for.

The changeset drops the removed-generics framing and the already-reverted
Timestamp jsonSchema bullet.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants