Repository: microsoft/kiota (csharp)

Issue:
Typescript client generation doesn't handle allOf correctly when serializing
### 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

I am trying to generate a typescript client for an API that receives polymorphic input described via the `allOf` property in the Open API document.

For the attached Open API document, Kiota generates the following `RequestsMetadata`
```ts
export const ReproRequestBuilderRequestsMetadata: RequestsMetadata = {
    post: {
        uriTemplate: ReproRequestBuilderUriTemplate,
        responseBodyContentType: "application/json",
        adapterMethodName: "send",
        responseBodyFactory:  createBaseTypeFromDiscriminatorValue,
        requestBodyContentType: "application/json",
        requestBodySerializer: serializeBaseType,
        requestInformationContentSetMethod: "setContentFromParsable",
    },
};
```

We can see that the `responseBodyFactory` is set to `createBaseTypeFromDiscriminatorValue` which correctly uses the discriminator value
```ts
export function createBaseTypeFromDiscriminatorValue(parseNode: ParseNode | undefined) : ((instance?: Parsable) => Record<string, (node: ParseNode) => void>) {
    if(!parseNode) throw new Error("parseNode cannot be undefined");
    const mappingValueNode = parseNode?.getChildNode("derivedType");
    if (mappingValueNode) {
        const mappingValue = mappingValueNode.getStringValue();
        if (mappingValue) {
            switch (mappingValue) {
                case "A":
                    return deserializeIntoDerivedTypeA;
                case "B":
                    return deserializeIntoDerivedTypeB;
            }
        }
    }
    return deserializeIntoBaseType;
}
```

However the `requestBodySerializer` is set to `serializeBaseType` which only serializes the properties defined in `BaseType`
```ts
export function serializeBaseType(writer: SerializationWriter, baseType: Partial<BaseType> | undefined | null = {}) : void {
    if (baseType) {
        writer.writeStringValue("derivedType", baseType.derivedType);
    }
}

// The following methods are generated but not used anywhere in the generated code
export function serializeDerivedTypeA(writer: SerializationWriter, derivedTypeA: Partial<DerivedTypeA> | undefined | null = {}) : void {
    if (derivedTypeA) {
        serializeBaseType(writer, derivedTypeA)
        writer.writeStringValue("typeAProperty", derivedTypeA.typeAProperty);
        writer.writeAdditionalData(derivedTypeA.additionalData);
    }
}

export function serializeDerivedTypeB(writer: SerializationWriter, derivedTypeB: Partial<DerivedTypeB> | undefined | null = {}) : void {
    if (derivedTypeB) {
        serializeBaseType(writer, derivedTypeB)
        writer.writeStringValue("typeBProperty", derivedTypeB.typeBProperty);
        writer.writeAdditionalData(derivedTypeB.additionalData);
    }
}
```

This means if we try to send one of the derived types to the post endpoint, it will never serialize the additional properties but only the properties on the base type
```ts
const request: DerivedTypeA = {
    derivedType: 'A',
    typeAProperty: 'valueA',
};

const response = await apiClient.repro.post(request);
// Sends request body containing the following, typeAProperty is ignored
// {
//   "derivedType": "A"
// }
```

### Expected behavior

Serialization and deserialization should both support the use of the discriminator property as defined in the swagger doc. This could look similar to the way that `oneOf` is currently implemented with Kiota code generation?
```ts
export function serializeBaseType(writer: SerializationWriter, baseType: Partial<DerivedTypeA | DerivedTypeB> | undefined | null = {}) : void {
    if (baseType === undefined || baseType === null) return;
    switch (baseType.derivedType) {
        case "A":
            serializeDerivedTypeA(writer, baseType as DerivedTypeA);
            break;
        case "B":
            serializeDerivedTypeB(writer, baseType as DerivedTypeB);
            break;
    }
}
```

### How to reproduce

1. Unzip the attached swagger.yml file to a folder
2. In that folder, run
    ```
    kiota generate --openapi swagger.yml --language typescript --output ./typescript
    ```
3. Open `./typescript/models/index.ts` and observe the `serializeBaseType` method is generated as described

### Open API description file

[swagger.zip](https://github.com/user-attachments/files/19969673/swagger.zip)

### Kiota Version

1.25.1+1d771798165084d73f745111fd99df79bbea913c

### Latest Kiota version known to work for scenario above?(Not required)

_No response_

### Known Workarounds

We can modify the generated code after the fact to replace the `serializeBaseType` method with the suggested code. However this requires us to manually modify the files after every generation.

### Configuration

- OS: Windows 11
- Architecture: x64

### Debug output

<details><summary>Click to expand log</summary>
```


Warning: the TypeScript language is in preview (Preview) some features are not fully supported and source breaking changes will happen with future updates.
dbug: Kiota.Builder.KiotaBuilder[0]
      kiota version 1.25.1
info: Kiota.Builder.KiotaBuilder[0]
      loaded description from local source
dbug: Kiota.Builder.KiotaBuilder[0]
      step 1 - reading the stream - took 00:00:00.0069358
warn: Kiota.Builder.KiotaBuilder[0]
      OpenAPI warning: #/ - A servers entry (v3) or host + basePath + schemes properties (v2) was not present in the OpenAPI description. The root URL will need to be set manually with the request adapter.
dbug: Kiota.Builder.KiotaBuilder[0]
      step 2 - parsing the document - took 00:00:00.0889994
dbug: Kiota.Builder.KiotaBuilder[0]
      step 3 - updating generation configuration from kiota extension - took 00:00:00.0000761
dbug: Kiota.Builder.KiotaBuilder[0]
      step 4 - filtering API paths with patterns - took 00:00:00.0044550
warn: Kiota.Builder.KiotaBuilder[0]
      No server url found in the OpenAPI document. The base url will need to be set when using the client.
dbug: Kiota.Builder.KiotaBuilder[0]
      step 5 - checking whether the output should be updated - took 00:00:00.0178133
dbug: Kiota.Builder.KiotaBuilder[0]
      step 6 - create uri space - took 00:00:00.0030187
dbug: Kiota.Builder.KiotaBuilder[0]
      InitializeInheritanceIndex 00:00:00.0027230
dbug: Kiota.Builder.KiotaBuilder[0]
      CreateRequestBuilderClass 00:00:00
dbug: Kiota.Builder.KiotaBuilder[0]
      MapTypeDefinitions 00:00:00.0036891
dbug: Kiota.Builder.KiotaBuilder[0]
      TrimInheritedModels 00:00:00
dbug: Kiota.Builder.KiotaBuilder[0]
      CleanUpInternalState 00:00:00
dbug: Kiota.Builder.KiotaBuilder[0]
      step 7 - create source model - took 00:00:00.0572555
dbug: Kiota.Builder.KiotaBuilder[0]
      37ms: Language refinement applied
dbug: Kiota.Builder.KiotaBuilder[0]
      step 8 - refine by language - took 00:00:00.0375099
dbug: Kiota.Builder.KiotaBuilder[0]
      step 9 - writing files - took 00:00:00.0320194
info: Kiota.Builder.KiotaBuilder[0]
      loaded description from local source
dbug: Kiota.Builder.KiotaBuilder[0]
      step 10 - writing lock file - took 00:00:00.0138642
Generation completed successfully
dbug: Kiota.Builder.KiotaBuilder[0]
      Api manifest path: C:\Repos\KiotaBugRepro\apimanifest.json

Hint: use the info command to get the list of dependencies you need to add to your project.
Example: kiota info -d "C:\Repos\KiotaBugRepro\swagger.yml" -l TypeScript

Hint: use the --include-path and --exclude-path options with glob patterns to filter the paths generated.
Example: kiota generate --include-path "**/foo" -d "C:\Repos\KiotaBugRepro\swagger.yml"


```
</details>


### Other information

_No response_

Pull request description:
fixes #6511

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b43ce63297..01c636231f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Fixes generation of usings/imports in where Date Types are placed in a nested class. [#6286](https://github.com/microsoft/kiota/issues/6286)
 - Python: Set a default value for non-nullable array fields. [#6350](https://github.com/microsoft/kiota/issues/6350)
 - Fixed a bug causing an error in generation of requests which have an enum or an UntypedNode as body. [microsoft/kiota-dotnet#537](https://github.com/microsoft/kiota-dotnet/issues/537)
+- Removed redundant additional data property definition in TypeScript.
+- Fixed a bug where the value parameter for serialization/deserialization in TypeScript methods would be missing a doc comment.
+- Fixed a bug where serializing a base type in TypeScript would lead to missing properties from the derived type. [#6511](https://github.com/microsoft/kiota/issues/6511)
 
 ## [1.27.0] - 2025-06-11
 
diff --git a/src/Kiota.Builder/CodeDOM/CodeParameter.cs b/src/Kiota.Builder/CodeDOM/CodeParameter.cs
index 711eecf81c..9a23b66659 100644
--- a/src/Kiota.Builder/CodeDOM/CodeParameter.cs
+++ b/src/Kiota.Builder/CodeDOM/CodeParameter.cs
@@ -3,6 +3,7 @@
 using System.Linq;
 
 namespace Kiota.Builder.CodeDOM;
+
 public enum CodeParameterKind
 {
     Custom,
@@ -56,6 +57,12 @@ public enum CodeParameterKind
     /// When the deserialization method is replaced as a function, this is the parameter representing instance we're deserializing into.
     /// </summary>
     DeserializationTarget,
+    /// <summary>
+    /// A parameter representing the derived type to be used for serialization when the type is a discriminator value.
+    /// This is used to ensure derived properties are serialized correctly when the type is a discriminator value and we're using the base type serialization method.
+    /// This is only used for languages that use static functions for the serialization as opposed to instance methods since the OOP inheritance correctly handles that case.
+    /// </summary>
+    SerializingDerivedType,
 }
 
 public class CodeParameter : CodeTerminalWithKind<CodeParameterKind>, ICloneable, IDocumentedElement, IDeprecableElement
diff --git a/src/Kiota.Builder/OrderComparers/BaseCodeParameterOrderComparer.cs b/src/Kiota.Builder/OrderComparers/BaseCodeParameterOrderComparer.cs
index c350366388..cca28cac65 100644
--- a/src/Kiota.Builder/OrderComparers/BaseCodeParameterOrderComparer.cs
+++ b/src/Kiota.Builder/OrderComparers/BaseCodeParameterOrderComparer.cs
@@ -2,6 +2,7 @@
 using Kiota.Builder.CodeDOM;
 
 namespace Kiota.Builder.OrderComparers;
+
 public class BaseCodeParameterOrderComparer : BaseStringComparisonComparer<CodeParameter>
 {
     public override int Compare(CodeParameter? x, CodeParameter? y)
@@ -34,7 +35,8 @@ protected virtual int GetKindOrderHint(CodeParameterKind kind)
             CodeParameterKind.SetterValue => 10,
             CodeParameterKind.ParseNode => 11,
             CodeParameterKind.Custom => 12,
-            _ => 13,
+            CodeParameterKind.SerializingDerivedType => 13,
+            _ => 14,
         };
     }
     private const int OptionalWeight = 10000;
diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
index 6239cfa2f0..a4299dd7de 100644
--- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
+++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
@@ -897,6 +897,18 @@ private static void CreateSerializationFunctions(CodeClass modelClass)
         {
             Name = $"{ModelSerializerPrefix}{modelClass.Name.ToFirstCharacterUpperCase()}",
         };
+        serializerMethod.AddParameter(new CodeParameter
+        {
+            Name = "isSerializingDerivedType",
+            DefaultValue = "false",
+            Type = new CodeType { Name = "boolean", IsExternal = true, IsNullable = false },
+            Kind = CodeParameterKind.SerializingDerivedType,
+            Documentation = new CodeDocumentation
+            {
+                DescriptionTemplate = "A boolean indicating whether the serialization is for a derived type.",
+            },
+            Optional = true,
+        });
 
         var deserializerFunction = new CodeFunction(deserializerMethod)
         {
@@ -923,6 +935,12 @@ private static void AddInterfaceParamToSerializer(CodeInterface modelInterface,
             DefaultValue = "{}",
             Type = new CodeType { Name = GetFinalInterfaceName(modelInterface), TypeDefinition = modelInterface },
             Kind = CodeParameterKind.DeserializationTarget,
+            Documentation = new CodeDocumentation
+            {
+                DescriptionTemplate = codeFunction.OriginalLocalMethod.Kind is CodeMethodKind.Deserializer ?
+                                            "The instance to deserialize into." :
+                                            "The instance to serialize from.",
+            },
         });
 
         if (modelInterface.Parent is not null)
diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs
index 6b58b9b2a0..5ea97f8f61 100644
--- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs
+++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs
@@ -398,10 +398,11 @@ private void WriteSerializerFunction(CodeFunction codeElement, LanguageWriter wr
             } param)
             throw new InvalidOperationException("Interface parameter not found for code interface");
 
-        writer.StartBlock($"if ({param.Name.ToFirstCharacterLowerCase()}) {{");
+        var serializingDerivedTypeParam = codeElement.OriginalLocalMethod.Parameters.FirstOrDefault(static x => x.Kind is CodeParameterKind.SerializingDerivedType) ?? throw new InvalidOperationException("Serializing derived type parameter not found");
+        writer.WriteLine($"if (!{param.Name.ToFirstCharacterLowerCase()} || {serializingDerivedTypeParam.Name}) {{ return; }}");
         if (codeInterface.StartBlock.Implements.FirstOrDefault(static x => x.TypeDefinition is CodeInterface) is CodeType inherits)
         {
-            writer.WriteLine($"serialize{inherits.TypeDefinition!.Name.ToFirstCharacterUpperCase()}(writer, {param.Name.ToFirstCharacterLowerCase()})");
+            writer.WriteLine($"serialize{inherits.TypeDefinition!.Name.ToFirstCharacterUpperCase()}(writer, {param.Name.ToFirstCharacterLowerCase()}, {serializingDerivedTypeParam.Name})");
         }
 
         foreach (var otherProp in codeInterface.Properties.Where(static x => x.IsOfKind(CodePropertyKind.Custom) && !x.ExistsInBaseType && !x.ReadOnly))
@@ -411,7 +412,33 @@ private void WriteSerializerFunction(CodeFunction codeElement, LanguageWriter wr
 
         if (codeInterface.GetPropertyOfKind(CodePropertyKind.AdditionalData) is CodeProperty additionalDataProperty)
             writer.WriteLine($"writer.writeAdditionalData({codeInterface.Name.ToFirstCharacterLowerCase()}.{additionalDataProperty.Name.ToFirstCharacterLowerCase()});");
-        writer.CloseBlock();
+
+        if (codeElement.OriginalMethodParentClass.DiscriminatorInformation.HasBasicDiscriminatorInformation &&
+            FindDiscriminatorPropertyBySerializationName(codeInterface, codeElement.OriginalMethodParentClass.DiscriminatorInformation.DiscriminatorPropertyName) is { } discriminatorProperty)
+        {
+            writer.StartBlock($"switch ({param.Name.ToFirstCharacterLowerCase()}.{discriminatorProperty.Name.ToFirstCharacterLowerCase()}) {{");
+            foreach (var mapping in codeElement.OriginalMethodParentClass.DiscriminatorInformation.DiscriminatorMappings)
+            {
+                var mappedType = mapping.Value;
+                writer.StartBlock($"case \"{mapping.Key}\":");
+                writer.WriteLine($"serialize{mappedType.Name.ToFirstCharacterUpperCase()}(writer, {param.Name.ToFirstCharacterLowerCase()} as {mappedType.Name.ToFirstCharacterUpperCase()}, true);");
+                writer.CloseBlock("break;");
+            }
+            writer.CloseBlock();
+        }
+    }
+    private static CodeProperty? FindDiscriminatorPropertyBySerializationName(CodeInterface codeInterface, string serializationName)
+    {
+        if (string.IsNullOrEmpty(serializationName)) return null;
+        if (codeInterface.Properties.FirstOrDefault(prop => prop.WireName.EqualsIgnoreCase(serializationName)) is { } discriminatorProperty)
+            return discriminatorProperty;
+        if (codeInterface.StartBlock.Implements.Any())
+            return codeInterface.StartBlock.Implements
+                .Select(x => x.TypeDefinition)
+                .OfType<CodeInterface>()
+                .Select(x => FindDiscriminatorPropertyBySerializationName(x, serializationName))
+                .FirstOrDefault(x => x is not null);
+        return null;
     }
 
     private static bool IsCollectionOfEnum(CodeProperty property)
diff --git a/src/Kiota.Builder/Writers/TypeScript/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodePropertyWriter.cs
index 557925f7d8..77a70e3e9d 100644
--- a/src/Kiota.Builder/Writers/TypeScript/CodePropertyWriter.cs
+++ b/src/Kiota.Builder/Writers/TypeScript/CodePropertyWriter.cs
@@ -4,6 +4,7 @@
 using static Kiota.Builder.Writers.TypeScript.TypeScriptConventionService;
 
 namespace Kiota.Builder.Writers.TypeScript;
+
 public class CodePropertyWriter : BaseElementWriter<CodeProperty, TypeScriptConventionService>
 {
     public CodePropertyWriter(TypeScriptConventionService conventionService) : base(conventionService) { }
@@ -13,6 +14,12 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w
         ArgumentNullException.ThrowIfNull(writer);
         if (codeElement.ExistsInExternalBaseType)
             return;
+
+        if (codeElement.Kind is CodePropertyKind.AdditionalData && codeElement.Parent is CodeInterface)
+        {
+            // additional data is already defined in the parent interface, no need to redefine it
+            return;
+        }
         var returnType = GetTypescriptTypeString(codeElement.Type, codeElement, inlineComposedTypeString: true);
         var isFlagEnum = codeElement.Type is CodeType { TypeDefinition: CodeEnum { Flags: true } }
                          && !codeElement.Type.IsCollection;//collection of flagged enums are not supported/don't make sense
@@ -35,7 +42,6 @@ private static void WriteCodePropertyForInterface(CodeProperty codeElement, Lang
                 writer.WriteLine($"get {codeElement.Name.ToFirstCharacterLowerCase()}(): {returnType};");
                 break;
             case CodePropertyKind.QueryParameter:
-            case CodePropertyKind.AdditionalData:
                 writer.WriteLine($"{codeElement.Name.ToFirstCharacterLowerCase()}?: {returnType}{(isFlagEnum ? "[]" : string.Empty)};");
                 break;
             default:
diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs
index 439309c607..7e24bec8fe 100644
--- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs
+++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs
@@ -9,6 +9,7 @@
 using static Kiota.Builder.Refiners.TypeScriptRefiner;
 
 namespace Kiota.Builder.Writers.TypeScript;
+
 public class TypeScriptConventionService : CommonLanguageConventionService
 {
 #pragma warning disable CA1707 // Remove the underscores
@@ -111,7 +112,7 @@ public override string GetParameterSignature(CodeParameter parameter, CodeElemen
         {
             (false, CodeParameterKind.DeserializationTarget, false) when parameter.Parent is CodeMethod codeMethod && codeMethod.Kind is CodeMethodKind.Serializer
                 => $" | null = {parameter.DefaultValue}",
-            (false, CodeParameterKind.DeserializationTarget, false) => $" = {parameter.DefaultValue}",
+            (false, CodeParameterKind.DeserializationTarget or CodeParameterKind.SerializingDerivedType, false) => $" = {parameter.DefaultValue}",
             (false, _, false) => $" = {parameter.DefaultValue} as {paramType}",
             _ => string.Empty,
         };


Test patch:
diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs
index f40428c05e..cf91454e68 100644
--- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs
@@ -436,7 +436,7 @@ public async Task WritesInheritedSerializerBodyAsync()
         var serializeFunction = root.FindChildByName<CodeFunction>($"Serialize{parentClass.Name.ToFirstCharacterUpperCase()}");
         writer.Write(serializeFunction);
         var result = tw.ToString();
-        Assert.Contains($"serialize{inheritedClass.Name.ToFirstCharacterUpperCase()}(writer, parentClass)", result);
+        Assert.Contains($"serialize{inheritedClass.Name.ToFirstCharacterUpperCase()}(writer, parentClass, isSerializingDerivedType)", result);
         Assert.DoesNotContain("definedInParent", result, StringComparison.OrdinalIgnoreCase);
     }
     [Fact]
@@ -461,10 +461,49 @@ public async Task WritesSerializerBodyAsync()
         Assert.Contains("writeCollectionOfObjectValues", result);
         Assert.Contains("serializeSomeComplexType", result);
         Assert.Contains("writeEnumValue", result);
-        Assert.Contains($"writer.writeAdditionalData", result);
+        Assert.Contains("writer.writeAdditionalData", result);
+        Assert.Contains($"if (!{parentClass.Name.ToFirstCharacterLowerCase()} || isSerializingDerivedType) {{ return; }}", result);
         Assert.Contains("definedInParent", result, StringComparison.OrdinalIgnoreCase);
     }
 
+    [Fact]
+    public async Task WritesSerializerBodyWithDiscriminatorAsync()
+    {
+        var generationConfiguration = new GenerationConfiguration { Language = GenerationLanguage.TypeScript };
+        var parentClass = TestHelper.CreateModelClassInModelsNamespace(generationConfiguration, root, "parentClass");
+        parentClass.DiscriminatorInformation.DiscriminatorPropertyName = "@odata.type";
+        parentClass.DiscriminatorInformation.AddDiscriminatorMapping("ns.childclass", new CodeType
+        {
+            Name = "childClass",
+            TypeDefinition = TestHelper.CreateModelClassInModelsNamespace(generationConfiguration, root, "childClass", true),
+        });
+        parentClass.AddProperty(new CodeProperty
+        {
+            Name = "odataType",
+            Kind = CodePropertyKind.Custom,
+            Type = new CodeType
+            {
+                Name = "string",
+            },
+            SerializationName = "@odata.type",
+        });
+        var method = TestHelper.CreateMethod(parentClass, MethodName, ReturnTypeName);
+        method.Kind = CodeMethodKind.Serializer;
+        method.IsAsync = false;
+        TestHelper.AddSerializationPropertiesToModelClass(parentClass);
+        await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.TypeScript }, root);
+        var serializeFunction = root.FindChildByName<CodeFunction>($"Serialize{parentClass.Name.ToFirstCharacterUpperCase()}");
+        Assert.NotNull(serializeFunction);
+        var parentNS = serializeFunction.GetImmediateParentOfType<CodeNamespace>();
+        Assert.NotNull(parentNS);
+        parentNS.TryAddCodeFile("foo", serializeFunction);
+        writer.Write(serializeFunction);
+        var result = tw.ToString();
+        Assert.Contains("switch (parentClass.odataType) {", result);
+        Assert.Contains("case \"ns.childclass\":", result);
+        Assert.Contains("serializeChildClass(writer, parentClass as ChildClass, true);", result);
+    }
+
     [Fact]
     public async Task WritesSerializerBodyWithDefaultAsync()
     {
@@ -976,6 +1015,15 @@ public void WritesReturnType()
                 TypeDefinition = targetInterface,
             }
         });
+        method.AddParameter(new CodeParameter
+        {
+            Name = "isDerivedSerialization",
+            Type = new CodeType
+            {
+                Name = "boolean",
+            },
+            Kind = CodeParameterKind.SerializingDerivedType,
+        });
         var function = new CodeFunction(method);
         root.TryAddCodeFile("foo", function);
         writer.Write(function);
@@ -1011,6 +1059,15 @@ public void DoesNotAddUndefinedOnNonNullableReturnType()
                 TypeDefinition = targetInterface,
             }
         });
+        method.AddParameter(new CodeParameter
+        {
+            Name = "isDerivedSerialization",
+            Type = new CodeType
+            {
+                Name = "boolean",
+            },
+            Kind = CodeParameterKind.SerializingDerivedType,
+        });
         method.ReturnType.IsNullable = false;
         var function = new CodeFunction(method);
         root.TryAddCodeFile("foo", function);
@@ -1045,6 +1102,15 @@ public void DoesNotAddAsyncInformationOnSyncMethods()
                 TypeDefinition = targetInterface,
             }
         });
+        method.AddParameter(new CodeParameter
+        {
+            Name = "isDerivedSerialization",
+            Type = new CodeType
+            {
+                Name = "boolean",
+            },
+            Kind = CodeParameterKind.SerializingDerivedType,
+        });
         method.IsAsync = false;
         var function = new CodeFunction(method);
         root.TryAddCodeFile("foo", function);
@@ -1080,6 +1146,15 @@ public void WritesPublicMethodByDefault()
                 TypeDefinition = targetInterface,
             }
         });
+        method.AddParameter(new CodeParameter
+        {
+            Name = "isDerivedSerialization",
+            Type = new CodeType
+            {
+                Name = "boolean",
+            },
+            Kind = CodeParameterKind.SerializingDerivedType,
+        });
         var function = new CodeFunction(method);
         root.TryAddCodeFile("foo", function);
         writer.Write(function);
@@ -1114,6 +1189,15 @@ public void WritesPrivateMethod()
                 TypeDefinition = targetInterface,
             }
         });
+        method.AddParameter(new CodeParameter
+        {
+            Name = "isDerivedSerialization",
+            Type = new CodeType
+            {
+                Name = "boolean",
+            },
+            Kind = CodeParameterKind.SerializingDerivedType,
+        });
         var function = new CodeFunction(method);
         root.TryAddCodeFile("foo", function);
         writer.Write(function);
@@ -1148,6 +1232,15 @@ public void WritesProtectedMethod()
                 TypeDefinition = targetInterface,
             }
         });
+        method.AddParameter(new CodeParameter
+        {
+            Name = "isDerivedSerialization",
+            Type = new CodeType
+            {
+                Name = "boolean",
+            },
+            Kind = CodeParameterKind.SerializingDerivedType,
+        });
         var function = new CodeFunction(method);
         root.TryAddCodeFile("foo", function);
         writer.Write(function);
diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodePropertyWriterTests.cs
index 43ba825033..383dc1eb0d 100644
--- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodePropertyWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodePropertyWriterTests.cs
@@ -7,6 +7,7 @@
 using Xunit;
 
 namespace Kiota.Builder.Tests.Writers.TypeScript;
+
 public sealed class CodePropertyWriterTests : IDisposable
 {
     private const string DefaultPath = "./";
@@ -135,4 +136,13 @@ public void WritesCorrectTypeForProperty()
         var result = tw.ToString();
         Assert.Contains($"{PropertyName}?: ArrayBuffer | null", result);
     }
+    [Fact]
+    public void DoesNodeEmitAdditionalDataPropertyOnInterfaces()
+    {
+
+        property.Kind = CodePropertyKind.AdditionalData;
+        writer.Write(property);
+        var result = tw.ToString();
+        Assert.Empty(result);
+    }
 }