Skip to content

Correct TypeScript deserialization for discriminated union property types#7669

Open
jeffreybulanadi wants to merge 1 commit into
microsoft:mainfrom
jeffreybulanadi:ts-discriminated-union-property-deserialization-6615
Open

Correct TypeScript deserialization for discriminated union property types#7669
jeffreybulanadi wants to merge 1 commit into
microsoft:mainfrom
jeffreybulanadi:ts-discriminated-union-property-deserialization-6615

Conversation

@jeffreybulanadi
Copy link
Copy Markdown
Contributor

Summary

When a model property references a named oneOf schema with a discriminator (e.g. \WeatherForecast\ defined as \oneOf: [RainyDayForecast, SunnyDayForecast]\ with \discriminator.propertyName), the TypeScript deserializer was generating incorrect ??-chained subtype factory calls instead of delegating to the base type's discriminator factory function.

Root Cause

In \CodeFunctionWriter.WritePropertyDeserializationBlock, the \GetOriginalComposedType\ branch handled all composed-type properties identically by joining individual subtype factory calls with ??. This is correct for true anonymous unions (oneOf without discriminator) but wrong for named discriminated unions, where a base-type factory (\createXFromDiscriminatorValue) already handles discriminator-based subtype resolution.

Before

\\ ypescript
"forecasts": n => { weatherSummary.forecasts = n.getCollectionOfObjectValues(createRainyDayForecastFromDiscriminatorValue) ?? n.getCollectionOfObjectValues(createSunnyDayForecastFromDiscriminatorValue); },
"primaryForecast": n => { weatherSummary.primaryForecast = n.getObjectValue(createRainyDayForecastFromDiscriminatorValue) ?? n.getObjectValue(createSunnyDayForecastFromDiscriminatorValue); },
\\

After

\\ ypescript
"forecasts": n => { weatherSummary.forecasts = n.getCollectionOfObjectValues(createWeatherForecastFromDiscriminatorValue); },
"primaryForecast": n => { weatherSummary.primaryForecast = n.getObjectValue(createWeatherForecastFromDiscriminatorValue); },
\\

Changes

  • \src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs: added private helper \TypeHasBasicDiscriminatorInformation\ and updated \WritePropertyDeserializationBlock\ to use the base type factory when the property's composed type carries discriminator information.
  • \ ests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs: two new tests covering the collection-property and single-object-property cases, plus an end-to-end integration test.
  • \ ests/Kiota.Builder.Tests/OpenApiSampleFiles/DiscriminatedUnionPropertySample.cs: new OpenAPI YAML sample for the integration test.
  • \CHANGELOG.md: unreleased entry for this change.

Closes #6615

@jeffreybulanadi jeffreybulanadi requested a review from a team as a code owner May 1, 2026 21:42
@jeffreybulanadi jeffreybulanadi force-pushed the ts-discriminated-union-property-deserialization-6615 branch from 0570b32 to 89094bc Compare May 1, 2026 21:46
…ypes

When a model property is typed as a named oneOf schema that carries a
discriminator (e.g. WeatherForecast = oneOf[RainyDayForecast, SunnyDayForecast]
with discriminator), the generated TypeScript deserializer was incorrectly
chaining individual subtype factory calls with ??:

  n.getCollectionOfObjectValues(createRainyDayForecastFromDiscriminatorValue)
    ?? n.getCollectionOfObjectValues(createSunnyDayForecastFromDiscriminatorValue)

The fix detects when the composed property type has basic discriminator
information and routes those properties through GetDeserializationMethodName
on the base type, producing the correct output:

  n.getCollectionOfObjectValues<WeatherForecast>(createWeatherForecastFromDiscriminatorValue)

The same correction applies to single-object properties.

Closes microsoft#6615
@jeffreybulanadi jeffreybulanadi force-pushed the ts-discriminated-union-property-deserialization-6615 branch from 89094bc to 7887ea4 Compare May 1, 2026 21:47
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.

Incorrect deserialization logic for nested array of discriminated union types in TypeScript

1 participant