Is it possible to make typescript-ref DTO generator to respect nullable properties?

Viewed 722

I am trying to achieve valid DTO generation using typescript-ref utility from ServiceStack. Problem is: for nullable and reference properties it will not generate the default value definition.

There is C# definition of a DTO:

public class Data
{
    public int Value { get; set; }
    public int? OptionalValue { get; set; }
    public string Text { get; set; }
}

Generated typescript DTO will look like this:

export class Data
{
    public value: number;
    public optionalValue: number;
    public text: string;

    public constructor(init?: Partial<Data>) { (Object as any).assign(this, init); }
}

This will lead to static checking problems. You will not be able to set undefined or null value (whatever will be selected to represent C# null value) to those properties. Because of Partial constructor it is possible to just omit them, but still it isn't convenient.

Also TypeScript compiler will not know that those fields can have undefined value - this is where we will lose static checking for those DTOs completely.

I found MakePropertiesOptional: True documented option that will make every property in generated DTOs optional. But this not solving my problem but leads to more of them. Is there any more flexible ways to solve it?

I need to have generated DTO for above class to look like this:

export class Data
{
    public value: number;
    public optionalValue?: number;
    public text?: string;

    public constructor(init?: Partial<Data>) { (Object as any).assign(this, init); }
}
1 Answers

I've improved support for this in the latest ServiceStack v5.8.1 pre-relase now on MyGet.

The default implementation should now generate optional TypeScript properties for Nullable properties. So by default it will now generate:

export class Data
{
    public value: number;
    public optionalValue?: number;
    public text: string;

    public constructor(init?: Partial<Data>) { (Object as any).assign(this, init); }
}

To just have specific properties required and all other properties optional you can enable the MakePropertiesOptional: True option then mark which properties should be required with the [Required] attribute, e.g:

public class Data
{
    [Required]
    public int Value { get; set; }
    public int? OptionalValue { get; set; }
    public string Text { get; set; }
}

This will generate your desired:

export class Data
{
    // @Required()
    public value: number;

    public optionalValue?: number;
    public text?: string;

    public constructor(init?: Partial<Data>) { (Object as any).assign(this, init); }
}

Another option to make all reference and nullable properties optional and value types required is using the new IsPropertyOptional filter, e.g:

TypeScriptGenerator.IsPropertyOptional = (generator, type, prop) => 
    prop.IsValueType != true || prop.Type == typeof(Nullable<>).Name;

Or with the new PropertyTypeFilter you could instead make every property nullable, e.g:

TypeScriptGenerator.IsPropertyOptional = (generator, type, prop) => false;

TypeScriptGenerator.PropertyTypeFilter = (gen, type, prop) => 
    gen.GetPropertyType(prop, out var isNullable) + "|null";

Which is now what gets configured you set:

TypeScriptGenerator.UseNullableProperties = true;

Which will generate every property as nullable, e.g:

export class Data
{
    public value: number|null;
    public optionalValue: number|null;
    public text: string|null;

    public constructor(init?: Partial<Data>) { (Object as any).assign(this, init); }
}
Related