Fix oneOf deserialization ordering for TypeScript with inheritance hierarchy#7033
Merged
gavinbarron merged 8 commits intomainfrom Oct 30, 2025
Merged
Fix oneOf deserialization ordering for TypeScript with inheritance hierarchy#7033gavinbarron merged 8 commits intomainfrom
gavinbarron merged 8 commits intomainfrom
Conversation
- Add SortTypesByInheritance helper method to CodeFunctionWriter - Sort types by inheritance hierarchy (derived classes before base classes) - Support both CodeClass and CodeInterface (TypeScript uses interfaces after refinement) - Add test to verify inheritance-based ordering - All 152 TypeScript tests pass Co-authored-by: gavinbarron <7122716+gavinbarron@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix incorrect deserialization behavior in TypeScript client
Fix oneOf deserialization ordering for TypeScript with inheritance hierarchy
Oct 23, 2025
Contributor
Contributor
Contributor
|
@copilot please run dotnet format to correct formatting issues and commit the result |
- Remove trailing whitespace in CodeFunctionWriter.cs - Remove trailing whitespace in CodeFunctionWriterTests.cs Co-authored-by: gavinbarron <7122716+gavinbarron@users.noreply.github.com>
Contributor
Author
gavinbarron
approved these changes
Oct 30, 2025
MIchaelMainer
approved these changes
Oct 30, 2025
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When generating TypeScript clients from OpenAPI specs with
oneOfcontaining types with inheritance relationships, the deserialization logic only worked correctly for the first type in an alphabetically sorted list. This caused properties of derived types to be incorrectly placed inadditionalPropertiesinstead of being properly deserialized into the root object.For example, given a
oneOfcontainingDevice(base class) andManagedPrivilegedDevice(derived fromDevice):When receiving a
ManagedPrivilegedDevice, the deserialization would match the baseDevicetype first, causingManagedPrivilegedDevice-specific properties likeprivilegeLevelto be incorrectly placed inadditionalProperties.Root Cause
The
CodeComposedTypeBase.Typesproperty returns types ordered alphabetically by name. The deserialization code generation inCodeFunctionWriter.cs(line 654) used this alphabetically sorted list directly, ignoring inheritance relationships. This meant base classes could be checked before their derived classes, causing incorrect deserialization behavior.Solution
Added a
SortTypesByInheritancehelper method that uses topological sorting to order types by their inheritance hierarchy, ensuring derived classes are always checked before their base classes during deserialization:Updated the deserialization code generation to use this sorted list:
Result
Now when a
ManagedPrivilegedDeviceis received, it correctly matches the more specific type first, and all properties are properly deserialized to the root object.Testing
WritesOneOfWithInheritanceDeserializationAsyncto verify inheritance-based orderingCredit
Thanks to @gavinbarron for identifying the root cause and suggesting the sorting approach in the issue comments.
Fixes #6896
Original prompt
This section details on the original issue you should resolve
<issue_title>Incorrect deserialization behavior from generated TS Client with
oneOf.</issue_title><issue_description>### What are you generating using Kiota, clients or plugins?
API Client/SDK
In what context or format are you using Kiota?
Windows executable
Client library/SDK language
TypeScript
Describe the bug
This is to follow up the comment below:
Originally posted by @elliot-huffman in #2720
Issue Summary
Problem Area: Microsoft Kiota OpenAPI client code generator
Component: Deserialization logic for schemas using
oneOfSpec Reference: SHIELD.json#L1022 (https://github.com/Software-Hardware-Integration-Lab/OpenAPI/blob/8e8fabe8651c268258946ca1bc4c4788d2019880/specs/SHIELD.json#L1022)
Description
When generating TypeScript clients using Kiota from an OpenAPI schema that includes both direct properties and a oneOf construct, the deserialization behavior is incorrect.
The generated types appear correct.
However, at runtime, deserialization only works for the first type listed in the oneOf array.
If an object matching the second type is received, its properties are incorrectly placed into the additionalProperties map rather than being deserialized into the expected root object.
As a result, the schema-level properties are not present in the deserialized object when the second oneOf type is used.
We had opened a Microsoft Support ticket about this.
The support team routed us to the issue board here.
Support Service request number for your reference: 2509050040003673.
Expected behavior
The deserializer should correctly identify and instantiate any of the types listed in the oneOf array.
Schema-level properties should be preserved and placed on the root object regardless of which oneOf type is matched.
Actual Behavior
Only the first oneOf type is deserialized correctly.
Other types are ignored, and their properties are treated as additionalProperties.
How to reproduce
Open API description file
https://github.com/Software-Hardware-Integration-Lab/OpenAPI/blob/8e8fabe8651c268258946ca1bc4c4788d2019880/specs/SHIELD.json#L1022
Kiota Version
1.0.0-preview.97
Latest Kiota version known to work for scenario above?(Not required)
No response
Known Workarounds
No response
Configuration
No response
Debug output
Click to expand log
```