Skip to content

read-write-markers + root-types Generated types with read markers can't be used with openapi-fetch #2726

@Tri125

Description

@Tri125

openapi-typescript version

Unreleased v7.14.0 (commit: b04ec75)

Node.js version

24.12.0

OS + version

Windows 11

Description

The root types generated with read-write-markers and root-types can't really be used when interacting with openapi-fetch.

The schema won't be assignable to data when obtaining results from a GET.

Additionally, the schema won't be assignable to body when POSTing the data.

import createClient from "openapi-fetch";
import type { paths, SchemaPet } from "./openapi/openapi.js"; // generated by openapi-typescript

const client = createClient<paths>({ baseUrl: "http://localhost:3030/" });

const {data, error} = await client.GET("/pets/{petId}", {
    params: {
        path: {
            petId: "234"
        }
    }
})

if (data) {
    /*
    Types of property 'id' are incompatible.
    Type 'number' is not assignable to type '$Read<number>'.ts
   */
    const myCurrentPet: SchemaPet = data;
}

const myNewPet : SchemaPet = {
    // Forced to set the readOnly prop even though my intent is to POST it.
    id: {
        $read: 235
    },
    name: "Mittens",
    tag: "cat"
}

await client.POST("/pets/{petId}", {
    params: {
        path: {
            petId: "234"
        }
    },
    body: {
    /*
   Type '{ id: $Read<number>; name: string; tag?: string; }' is not assignable to type '{ id?: undefined; }'.
   */
        ...myNewPet
    }
})

Reproduction

I'm using the currently unreleased version commit: b04ec75.

# redocly.yaml
extends:
  - recommended

apis:
  core@v2:
    root: ./openapi.yaml
    x-openapi-ts:
      output: ./src/openapi/openapi.d.ts
      read-write-markers: true
      root-types: true
# openapi.yaml
openapi: 3.0.0
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
    url: https://test.test
servers:
  - url: http://localhost:3030
security: []
paths:
  /pets/{petId}:
    post:
      summary: Create a pet
      operationId: createPets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      tags:
        - pets
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
        required: true
      responses:
        '201':
          description: Null response
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Pet:
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: integer
          format: int64
          readOnly: true
        name:
          type: string
        tag:
          type: string
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: integer
          format: int32
        message:
          type: string
// index.ts

import createClient from "openapi-fetch";
import type { paths, SchemaPet } from "./openapi/openapi.js"; // generated by openapi-typescript

const client = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });

const {data, error} = await client.GET("/pets/{petId}", {
    params: {
        path: {
            petId: "234"
        }
    }
})

if (data) {
    const myCurrentPet : SchemaPet = data;
}

const myNewPet : SchemaPet = {
    id: {
        $read: 235
    },
    name: "Mittens",
    tag: "cat"
}

await client.POST("/pets/{petId}", {
    params: {
        path: {
            petId: "234"
        }
    },
    body: {
        ...myNewPet
    }
})

Expected result

I expected to be able to directly use the typing when interacting with openapi-fetch.

Perhaps there should be one generated schema type for readOnly and a second generated schema type for writeOnly?

Required

  • My OpenAPI schema is valid and passes the Redocly validator (npx @redocly/cli@latest lint)

Extra

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingopenapi-tsRelevant to the openapi-typescript library

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions