Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript generator: Use string type as the discriminator property type in specialized interfaces #1718

Merged
merged 3 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/NJsonSchema.CodeGeneration.Tests/EnumGenerationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ public async Task When_enum_has_string_value_then_TS_code_has_string_value()
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("_0562 = <any>\"0562\",", code);
Assert.Contains("_0532 = <any>\"0532\",", code);
Assert.Contains("_0562 = \"0562\",", code);
Assert.Contains("_0532 = \"0532\",", code);
}

public class ClassWithStringEnum
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//----------------------
// <auto-generated>
// </auto-generated>
//----------------------







export interface Base {
Type: EBase;
}

export enum EBase {
OneChild = "OneChild",
SecondChild = "SecondChild",
}

export interface OneChild extends Base {
A: string;
Type: EBase.OneChild;
}

export interface SecondChild extends Base {
B: string;
Type: EBase.SecondChild;
}

export interface MyClass {
Child: Base;
Children: Base[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//----------------------
// <auto-generated>
// </auto-generated>
//----------------------







export interface Base {
Type: EBase;
}

export type EBase = "OneChild" | "SecondChild";

export interface OneChild extends Base {
A: string;
Type: 'OneChild';
}

export interface SecondChild extends Base {
B: string;
Type: 'SecondChild';
}

export interface MyClass {
Child: Base;
Children: Base[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
//----------------------
// <auto-generated>
// </auto-generated>
//----------------------







export abstract class Base implements IBase {

protected _discriminator: string;

constructor(data?: IBase) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
this._discriminator = "Base";
}

init(_data?: any) {
}

static fromJS(data: any): Base {
data = typeof data === 'object' ? data : {};
if (data["Type"] === "OneChild") {
let result = new OneChild();
result.init(data);
return result;
}
if (data["Type"] === "SecondChild") {
let result = new SecondChild();
result.init(data);
return result;
}
throw new Error("The abstract class 'Base' cannot be instantiated.");
}

toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["Type"] = this._discriminator;
return data;
}
}

export interface IBase {
}

export class OneChild extends Base implements IOneChild {
a: string;
type: EBase;

constructor(data?: IOneChild) {
super(data);
this._discriminator = "OneChild";
}

init(_data?: any) {
super.init(_data);
if (_data) {
this.a = _data["A"];
this.type = _data["Type"];
}
}

static fromJS(data: any): OneChild {
data = typeof data === 'object' ? data : {};
let result = new OneChild();
result.init(data);
return result;
}

toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["A"] = this.a;
data["Type"] = this.type;
super.toJSON(data);
return data;
}
}

export interface IOneChild extends IBase {
a: string;
type: EBase;
}

export enum EBase {
OneChild = "OneChild",
SecondChild = "SecondChild",
}

export class SecondChild extends Base implements ISecondChild {
b: string;
type: EBase;

constructor(data?: ISecondChild) {
super(data);
this._discriminator = "SecondChild";
}

init(_data?: any) {
super.init(_data);
if (_data) {
this.b = _data["B"];
this.type = _data["Type"];
}
}

static fromJS(data: any): SecondChild {
data = typeof data === 'object' ? data : {};
let result = new SecondChild();
result.init(data);
return result;
}

toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["B"] = this.b;
data["Type"] = this.type;
super.toJSON(data);
return data;
}
}

export interface ISecondChild extends IBase {
b: string;
type: EBase;
}

export class MyClass implements IMyClass {
child: OneChild | SecondChild;
children: (OneChild | SecondChild)[];

constructor(data?: IMyClass) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}

init(_data?: any) {
if (_data) {
this.child = _data["Child"] ? OneChild | SecondChild.fromJS(_data["Child"]) : <any>undefined;
if (Array.isArray(_data["Children"])) {
this.children = [] as any;
for (let item of _data["Children"])
this.children.push(OneChild | SecondChild.fromJS(item));
}
}
}

static fromJS(data: any): MyClass {
data = typeof data === 'object' ? data : {};
let result = new MyClass();
result.init(data);
return result;
}

toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["Child"] = this.child ? this.child.toJSON() : <any>undefined;
if (Array.isArray(this.children)) {
data["Children"] = [];
for (let item of this.children)
data["Children"].push(item.toJSON());
}
return data;
}
}

export interface IMyClass {
child: OneChild | SecondChild;
children: (OneChild | SecondChild)[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//----------------------
// <auto-generated>
// </auto-generated>
//----------------------







export interface Base {
Type: string;
}

export interface OneChild extends Base {
A: string;
Type: EBase.OneChild;
}

export enum EBase {
OneChild = "OneChild",
SecondChild = "SecondChild",
}

export interface SecondChild extends Base {
B: string;
Type: EBase.SecondChild;
}

export interface MyClass {
Child: OneChild | SecondChild;
Children: (OneChild | SecondChild)[];
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
using System.Threading.Tasks;
using Newtonsoft.Json;
using NJsonSchema.Generation;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Xunit;
using NJsonSchema.NewtonsoftJson.Converters;
using NJsonSchema.NewtonsoftJson.Generation;
using VerifyXunit;
using Newtonsoft.Json.Converters;

namespace NJsonSchema.CodeGeneration.TypeScript.Tests
{
[UsesVerify]
public class TypeScriptDiscriminatorTests
{
[JsonConverter(typeof(JsonInheritanceConverter), nameof(Type))]
Expand All @@ -19,6 +21,7 @@ public abstract class Base
public abstract EBase Type { get; }
}

[JsonConverter(typeof(StringEnumConverter))]
public enum EBase
{
OneChild,
Expand Down Expand Up @@ -55,6 +58,7 @@ public async Task When_generating_interface_contract_add_discriminator()
GenerateAbstractProperties = true,
});
var data = schema.ToJson();
var json = JsonConvert.SerializeObject(new OneChild());

//// Act
var generator = new TypeScriptGenerator(schema, new TypeScriptGeneratorSettings
Expand All @@ -66,8 +70,9 @@ public async Task When_generating_interface_contract_add_discriminator()

//// Assert
Assert.Contains("export interface Base {\n Type: EBase;\n}", code);
await VerifyHelper.Verify(code);
}

[Fact]
public async Task When_generating_interface_contract_add_discriminator_string_literal()
{
Expand All @@ -89,6 +94,7 @@ public async Task When_generating_interface_contract_add_discriminator_string_li

//// Assert
Assert.Contains("export interface Base {\n Type: EBase;\n}", code);
await VerifyHelper.Verify(code);
}

[Fact]
Expand All @@ -112,8 +118,9 @@ public async Task When_parameter_is_abstract_then_generate_union_interface()
Assert.Contains("export interface SecondChild extends Base", code);
Assert.Contains("Child: OneChild | SecondChild;", code);
Assert.Contains("Children: (OneChild | SecondChild)[];", code);
await VerifyHelper.Verify(code);
}

[Fact]
public async Task When_parameter_is_abstract_then_generate_union_class()
{
Expand All @@ -135,6 +142,7 @@ public async Task When_parameter_is_abstract_then_generate_union_class()
Assert.Contains("export class SecondChild extends Base", code);
Assert.Contains("child: OneChild | SecondChild;", code);
Assert.Contains("children: (OneChild | SecondChild)[];", code);
await VerifyHelper.Verify(code);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ public List<EnumerationItemModel> Enums
entries.Add(new EnumerationItemModel
{
Name = _settings.EnumNameGenerator.Generate(i, name, value, _schema),
Value = _schema.Type.IsInteger() ?
value.ToString() :
(_settings.TypeScriptVersion < 2.4m ? "<any>" : "") + "\"" + value + "\"",
Value = _schema.Type.IsInteger() ? value.ToString() : "\"" + value + "\"",
});
}
}
Expand Down
Loading
Loading