Incorrect deserialization logic for nested array of discriminated union types in TypeScript
#6,615 opened on Jun 3, 2025
Repository metrics
- Stars
- (3,783 stars)
- PR merge metrics
- (PR metrics pending)
Description
What are you generating using Kiota, clients or plugins?
API Client/SDK
In what context or format are you using Kiota?
Nuget tool
Client library/SDK language
TypeScript
Describe the bug
The TypeScript generator creates incorrect deserialization logic for an array of a polymorphic type when that array is a property of another model. Instead of using the discriminator mapping for each element in the collection, the generated code attempts to deserialize the entire collection into one of the possible types, and then tries the next type if the first attempt fails. This results in incorrectly deserialized objects within the array.
This issue does not occur when an endpoint returns the array of the polymorphic type directly. In that case, the discriminator logic is applied correctly.
I also generated the corresponding C# client for the OpenAPI yaml which deserialized the nested array correctly, so this appears to be typescript related.
As an example I have the following model (csharp, for better readability, api definition is attached via the link):
public class WeatherForecastSummary
{
public List<WeatherForecast> Forecasts { get; set; } = [];
}
[JsonPolymorphic(TypeDiscriminatorPropertyName = "weatherType")]
[JsonDerivedType(typeof(RainyDayForecast), "Rain")]
[JsonDerivedType(typeof(SunnyDayForecast), "Sun")]
public abstract class WeatherForecast
{
public DateOnly Date { get; set; }
}
public class RainyDayForecast : WeatherForecast
{
public int RainfallAmount { get; set; }
}
public class SunnyDayForecast : WeatherForecast
{
public int TemperatureC { get; set; }
}
This is the incorrect code generated for the WeatherForecastSummary model's deserialization:
export function deserializeIntoWeatherForecastSummary(weatherForecastSummary: Partial<WeatherForecastSummary> | undefined = {}): Record<string, (node: ParseNode) => void> {
return {
"forecasts": n => {
weatherForecastSummary.forecasts =
n.getCollectionOfObjectValues<WeatherForecastRainyDayForecast>(createWeatherForecastRainyDayForecastFromDiscriminatorValue)
?? n.getCollectionOfObjectValues<WeatherForecastSunnyDayForecast>(createWeatherForecastSunnyDayForecastFromDiscriminatorValue);
},
}
}
This code tries to deserialize the entire forecasts array as WeatherForecastRainyDayForecast[] and if that doesn't work, it tries WeatherForecastSunnyDayForecast[].
For comparison, when the response is a direct array of WeatherForecast, Kiota correctly generates a factory method that uses the discriminator:
export function createWeatherForecastFromDiscriminatorValue(parseNode: ParseNode | undefined) : ((instance?: Parsable) => Record<string, (node: ParseNode) => void>) {
const mappingValueNode = parseNode?.getChildNode("weatherType");
if (mappingValueNode) {
const mappingValue = mappingValueNode.getStringValue();
if (mappingValue) {
switch (mappingValue) {
case "Rain":
return deserializeIntoWeatherForecastRainyDayForecast;
case "Sun":
return deserializeIntoWeatherForecastSunnyDayForecast;
}
}
}
return deserializeIntoWeatherForecast;
}
export const SummaryRequestBuilderRequestsMetadata: RequestsMetadata = {
get: {
uriTemplate: SummaryRequestBuilderUriTemplate,
responseBodyContentType: "application/json",
adapterMethodName: "send",
responseBodyFactory: createWeatherForecastSummaryFromDiscriminatorValue,
},
};
Expected behavior
The deserialization logic for the forecasts property within deserializeIntoWeatherForecastSummary should leverage the createWeatherForecastFromDiscriminatorValue factory for each item in the collection, not for the collection as a whole. The generated code should look more like this:
// Conceptual correct implementation
export function deserializeIntoWeatherForecastSummary(weatherForecastSummary: Partial<WeatherForecastSummary> | undefined = {}): Record<string, (node: ParseNode) => void> {
return {
"forecasts": n => {
weatherForecastSummary.forecasts = n.getCollectionOfObjectValues(createWeatherForecastFromDiscriminatorValue);
},
}
}
How to reproduce
I created a minimal working example in the following repo with instructions on how to run it: https://github.com/nreinartz/kiota-ts-incorrect-derserialization
Open API description file
https://github.com/nreinartz/kiota-ts-incorrect-derserialization/blob/main/openapi.json
Kiota Version
1.26.1
Latest Kiota version known to work for scenario above?(Not required)
No response
Known Workarounds
No response
Configuration
No response
Debug output
Other information
No response