Skip to content

fix: resolve nullable oneOf to the referenced type - #246

Merged
nikcio merged 1 commit into
Nikcio-labs:mainfrom
geirsagberg-udir:geir/nullable-ref-oneof
Nov 7, 2026
Merged

nikcio merged 1 commit into
Nikcio-labs:mainfrom
geirsagberg-udir:geir/nullable-ref-oneof

Conversation

@geirsagberg-udir

@geirsagberg-udir geirsagberg-udir commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

ASP.NET Core 10 emits a nullable reference property in OpenAPI 3.1 as a oneOf of null and a $ref:

"customer": {
  "oneOf": [
    { "type": "null" },
    { "description": "The customer, if any.", "$ref": "#/components/schemas/Customer" }
  ]
}

ResolveOneOf only handled a single variant, so this became object?. ResolveAnyOf already handled the [type, null] pattern. Both now share one helper:

 ResolveOneOf
   if hoisted union → hoisted type
   if one variant → that variant
+  if exactly one non-null variant → that variant, nullable
   else → object

 ResolveAnyOf
   if hoisted union → hoisted type
   if one variant → that variant
-  if exactly one non-null variant (inline check) → that variant, nullable
+  if exactly one non-null variant (shared helper) → that variant, nullable
   else → object

The nullability rules in type-mapping.md now list this pattern.

Complements #150, which hoists unions with two or more non-null variants. That PR filters out null before hoisting, so [null, $ref] still reaches ResolveOneOf and becomes object there. The new test fails on #150 too.

Evidence

New test Generate_FromText_OneOfNullAndRef_GeneratesNullableReference, using the spec above:

  • Before: fails — Not found: "public Customer? Customer { get; init; }" (generated public object? Customer)
    After: passes, with no OrderCustomer union hoisted, and the output compiles with warnings as errors.

dotnet test passes for the whole solution.

Merge Danger

Door: two-way

Blast Radius: generated-types

Consumers whose specs use oneOf: [null, X] get X? instead of object? when they regenerate. That is a type change in generated code, but it replaces a placeholder with the intended type. A oneOf with two or more non-null variants is unchanged.

ASP.NET Core 10 emits nullable reference properties in OpenAPI 3.1 as
oneOf: [{ type: null }, { $ref }]. ResolveOneOf only handled a single
variant, so these properties became object?. Apply the same
single-non-null-variant rule that anyOf already uses.
@nikcio
nikcio merged commit aebd044 into Nikcio-labs:main Nov 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants