cyclosproject / ng-openapi-gen

An OpenAPI 3.0 codegen for Angular
MIT License
399 stars 134 forks source link

models fail to compile if additionalProperties is combined with other fields #68

Closed JeroMiya closed 4 years ago

JeroMiya commented 4 years ago

There are often models defined as a set of fields plus an additionalProperties of various types, such as object. For example, here is the schema for a ProblemDetails model which is a representation of the RFC 7807 error response body:

      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": {
          "type": "object",
          "additionalProperties": false
        }

That is, the object has fields type, title, status, detail, instance, and can have additional properties of type object. ng-openapi-gen generates this model from the above schema:

export interface ProblemDetails {
  detail?: null | string;
  instance?: null | string;
  status?: null | number;
  title?: null | string;
  type?: null | string;

  [key: string]: {  };
}

Unfortunately this doesn't compile:

ERROR in src/app/api/models/problem-details.ts:3:3 - error TS2411: Property 'detail' of type 'string | null | undefined' is not assignable to string index type '{}'.

3   detail?: null | string;
    ~~~~~~
src/app/api/models/problem-details.ts:4:3 - error TS2411: Property 'instance' of type 'string | null | undefined' is not assignable to string index type '{}'.

4   instance?: null | string;
    ~~~~~~~~
src/app/api/models/problem-details.ts:5:3 - error TS2411: Property 'status' of type 'number | null | undefined' is not assignable to string index type '{}'.

5   status?: null | number;
    ~~~~~~
src/app/api/models/problem-details.ts:6:3 - error TS2411: Property 'title' of type 'string | null | undefined' is not assignable to string index type '{}'.

6   title?: null | string;
    ~~~~~
src/app/api/models/problem-details.ts:7:3 - error TS2411: Property 'type' of type 'string | null | undefined' is not assignable to string index type '{}'.

7   type?: null | string;
    ~~~~

This is because the indexer is only typed to the additionalProperties type. It also has to union in all the types of the other fields (or else just switch to any with a warning?):

export interface ProblemDetails {
  detail?: null | string;
  instance?: null | string;
  status?: null | number;
  title?: null | string;
  type?: null | string;

  [key: string]: null | string | number | undefined | {  };
}
luisfpg commented 4 years ago

This won't be trivial to implement, but let's see. Anyway, I'm still in vacations, and there is surely a pile of work to do when I'm back, so I can't set an ETA.

JeroMiya commented 4 years ago

Cool, have a good vacation! If adding this scenario to the any branch is easier to implement than calculating the proper union type, that would be an acceptable intermediate solution. Maybe with a warning?