Skip to content

[Bug]: TypeScript payloads preset emits non-compiling code (non-nullable date-time null fallback + nullable-array marshal) #373

Description

@ALagoni97

Description

Generating a TypeScript client from an OpenAPI spec produces payloads files that fail tsc. Generation reports zero errors; the breakage only appears when the generated package is built. Two independent defects in the payloads preset:

1. unmarshal() emits an unconditional null fallback for date-time fields.
For a required (non-nullable) date-time property the declared type is Date, but the deserializer produces Date | null.

TS2322: Type 'Date | null' is not assignable to type 'Date'.

2. marshal() guards a nullable array/object with !== undefined only, then iterates it.
For a type: ["null", "array"] property the field is T[] | null, so null slips past the guard.

TS2531: Object is possibly 'null'.

Environment

  • CLI Version: 0.72.0 (latest)
  • Node Version: v22.14.0
  • OS: Windows 11

Minimal Reproduction

codegen.ts

import { TheCodegenConfiguration } from '@the-codegen-project/cli'

const config: TheCodegenConfiguration = {
  inputType: 'openapi',
  inputPath: './input.openapi.json',
  language: 'typescript',
  generators: [{ preset: 'payloads', outputPath: './src/payloads', serializationType: 'json' }],
}

export default config

input.openapi.json

{
  "openapi": "3.1.1",
  "info": { "title": "Payloads repro", "version": "1.0.0" },
  "paths": {
    "/thing": {
      "get": {
        "operationId": "getThing",
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Thing" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Thing": {
        "type": "object",
        "required": ["created"],
        "properties": {
          "created": { "type": "string", "format": "date-time" },
          "signers": { "type": ["null", "array"], "items": { "type": "string" } }
        }
      }
    }
  }
}

Command

the-codegen-project generate && tsc --noEmit

Actual Output

Thing.ts:

private _created: Date;                 // required -> non-null
private _signers?: string[] | null;

public marshal(): string {
  // ...
  if(this.signers !== undefined) {      // does not exclude null
    for (const unionItem of this.signers) {   // TS2531: Object is possibly 'null'
      // ...
    }
  }
}

public static unmarshal(json: string | object): Thing {
  const obj = typeof json === "object" ? json : JSON.parse(json);
  const instance = new Thing({} as any);
  if (obj["created"] !== undefined) {
    instance.created = obj["created"] == null ? null : new Date(obj["created"]);  // TS2322: Date | null -> Date
  }
  // ...
}

Expected Output

  1. For a non-nullable date-time, drop the null branch so the value matches the declared Date:
instance.created = new Date(obj["created"]);
  1. Guard nullable array/object marshalling against null too:
if (this.signers !== undefined && this.signers !== null) {
  for (const unionItem of this.signers) { /* ... */ }
}

Additional Context

  • Discovered while publishing a real client; the publish pipeline runs npm run build (tsc) before npm publish, so these tsc errors abort publishing.
  • The ajv / ajv-formats import errors seen in isolation resolve after npm i and are unrelated to these two defects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions