Skip to content

feat(scalars): distinct input/output codegen types#3086

Draft
ifeanyi-ugwu wants to merge 6 commits into
graphql-hive:masterfrom
ifeanyi-ugwu:feat/codegen-input-output-scalars
Draft

feat(scalars): distinct input/output codegen types#3086
ifeanyi-ugwu wants to merge 6 commits into
graphql-hive:masterfrom
ifeanyi-ugwu:feat/codegen-input-output-scalars

Conversation

@ifeanyi-ugwu

Copy link
Copy Markdown
Contributor

Closes #2554. Emits distinct input (parsed) and output (resolver-return) codegen types for the 12 scalars where they differ, via the object form of codegenScalarType — e.g. DateTime: { input: Date; output: Date | string | number }, Port: { input: number; output: string | number }.

Draft — not ready to merge

Two dependencies:

What it does

Scalars whose parsed value is narrower than the values a resolver may return now declare both positions instead of collapsing them into one union:

input output scalars
Date Date | string | number DateTime, Timestamp
Date Date | string Date, Time
Buffer Buffer | string Byte
URL URL | string URL
bigint | number bigint | number | string BigInt
number string | number Port, Latitude, Longitude

DateTimeISO and Long inherit their base configs.

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.
…and returned differ

Scalars whose parsed (input) type is narrower than the accepted resolver-return
(output) type declare codegenScalarType as { input, output }: DateTime, Date,
Time, Timestamp, Byte, URL, BigInt, Port, Latitude and Longitude (DateTimeISO
and Long inherit). For example DateTime emits
{ input: Date; output: Date | string | number } and Port emits
{ input: number; output: string | number }.

Depends on the object-form codegenScalarType support added in
graphql-code-generator#10893; older codegen reads the extension as a single
string.
@ardatan

ardatan commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

This would be a breaking change imo. So it probably needs a major release.

The object form is a format change to codegenScalarType, not a value
change. Released graphql-code-generator reads the extension as a string
and cannot parse the object, so regenerating against current codegen
breaks.
@ifeanyi-ugwu

Copy link
Copy Markdown
Contributor Author

This would be a breaking change imo. So it probably needs a major release.

Agreed, i've bumped the changeset to major.

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.

Improve codegen related extensions

2 participants