RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.76k stars 1.29k forks source link

Inconsistent undefined in properties #4303

Open skinnyskinner opened 1 year ago

skinnyskinner commented 1 year ago

In my config I want to use the /NullValue:Undefined cli option for the generation of a Angular Api Client.

This was no real issue before, since I had strict disabled in my tsconfig, but since I changed it we found an issue.

When I use undefined as our nullvalue, object types get a null check.

_data['endDate'] ? moment(_data['endDate'].toString()) : <any>undefined;

The issue now is that the string does not get such a check. And I also think other primitive values suffer from the same fate.

So from the backend I get a null from the api call. image

The property is defined with undefined.

export class DetailItem {
    dueDate?: moment.Moment | undefined;
    followUpComment?: string | undefined;

    ...
}

But in the assign from the value we are missing the null check.

this.followUpComment = _data['followUpComment'];

for objects this happens with a check.

this.dueDate = _data['dueDate'] ? moment(_data['dueDate'].toString()) : <any>undefined;

So the desired behaviour would be the same as for an object for primitive types, or something simliar to this:

this.followUpComment = _data['followUpComment'] ?? <any>undefined;

That way i can be sure the value is undefined and not null. Since null should not even be allowed from the configuration.

The issue is similar to this discussion. https://github.com/RicoSuter/NSwag/issues/926#issuecomment-327509835

dipenpdev commented 1 year ago

Having the same issue which inevitably raises null/undefined exceptions. Generating using swagger.json and (latest) NSwagStudio v13.20.0.0:

Example swagger.json snippet:

      "Foo": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "Dates": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string",
              "format": "date-time",
              "nullable": true
            }

Generates the following typescript:

export class Foo implements IFoo {
    dates?: (Date | undefined)[] | undefined; // Correct: Defines dates array as potentially containing undefined elements

    // ...

    init(_data?: any) {
        if (_data) {
            if (Array.isArray(_data["dates"])) {
                this.dates = [] as any;
                for (let item of _data["dates"])
                    this.dates!.push(new Date(item)); // Correct: Initialises (Date | undefined) array with potentially undefined dates at their expected indexes
            }

    // ...

    }

    // ...

    toJSON(data?: any) {
        data = typeof data === 'object' ? data : {};
        if (Array.isArray(this.dates)) {
            data["dates"] = [];
            for (let item of this.dates)
                data["dates"].push(item.toISOString()); // Incorrect: item may be null/undefined and is never checked, toISOString() throws
        }

        // ...
    }
}