Are there any alternative OpenAPI schemas that can produce more favorable Flow/TypeScript types, as the `oneOf` keyword is currently generating undesirable types?

We possess an OpenAPI schema that looks like this:

{
    "openapi": "3.0.1",
    "paths": {
        "/v1/tool/breadcrumbs/{hierarchyId}/{categoryId}": {
            "get": {
                "tags": [
                    "V1-tool"
                ],
                "summary": "Get Breadcrumbs details",
                "operationId": "getBreadcrumbs",
                "parameters": [
                    {
                        "name": "hierarchyId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "minimum": 1,
                            "type": "integer",
                            "format": "int32"
                        }
                    },
                    {
                        "name": "categoryId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "minimum": 1,
                            "type": "integer",
                            "format": "int32"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "default response",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "$ref": "#/components/schemas/Kitten"
                                    }
                                }
                            }
                        }
                    }
                },
                "security": [
                    {
                        "Auth": []
                    }
                ]
            }
        },
        ...

We execute the following command to produce Flow types from the above schema file:

npx swagger-to-flowtype path/to/schema/file -d generated_types.js

The outcome of this process is seen below:

// @flow strict
export type Kitten = { type: "Kitten", id: number, name: string, uri: string };
export type HierarchyResponse = { type: "Hierarchy", id: number, name: string };
...

One issue arises with the Item type, which is currently defined as:

export type Item = { type: string };

Instead, we desire it to be defined like so:

export type Item = ChildCategoryResponse | AliasCategoryResponse | SubheaderResponse;

Upon examining our OpenAPI schema, we found the relevant section:

"Item": {
    // properties and oneOf definitions
},

Even though we expected a different output for the Item type during generation using swagger-to-flowtype, similar issues were observed when generating TypeScript types.

A concrete example showcasing items array is given below:

const items: Array<Item> = [
  {
    type: "Alias",
    level: "3",
    name: "name",
    id: 42,
    uri: "uri"
  },
  ...
]

It's evident why the current definition

export type Item = { type: string };
is incorrect and should instead reflect
export type Item = ChildCategoryResponse | AliasCategoryResponse | SubheaderResponse
.

Question:

Is there a way to adjust the schema to generate the desired

export type Item = ChildCategoryResponse | AliasCategoryResponse | SubheaderResponse
representation?

Answer №1

After going through the OpenAPI specification, it appears that the use of both oneOf and type together is not recommended. The examples in the specification only utilize one or the other, but never both simultaneously. It seems like when the TypeScript binding generator encounters a type value of "object", it bases the type on properties and disregards the presence of oneOf.

If you wish to differentiate the types within the union using the type property, consider using discriminator instead of properties:

"Item": {
    "oneOf": [
        {
            "$ref": "#/components/schemas/ChildCategoryResponse"
        },
        {
            "$ref": "#/components/schemas/AliasCategoryResponse"
        },
        {
            "$ref": "#/components/schemas/SubheaderResponse"
        }
    ],
    "discriminator": {
        "propertyName": "type",
        "mapping": {
            "Category": {
                "$ref": "#/components/schemas/ChildCategoryResponse"
            },
            "Alias": {
                "$ref": "#/components/schemas/AliasCategoryResponse"
            },
            "Subheader": {
                "$ref": "#/components/schemas/SubheaderResponse"
            }
        }
    }
},

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The angular2 error message indicating a property cannot be read if it is

Encountering an issue trying to utilize a method within an angular2 component. Here's the code snippet : import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { AgGridModule } from &ap ...

Error: The property 'children' is not found in type '{ children?: ReactNode; }'

I have been working on implementing the search bar feature from the provided link. Despite my efforts to match the types correctly, I keep encountering a TypeScript error. Homepage.tsx const [searchQuery, setSearchQuery] = useState(query || '' ...

Developing a TypeScript PureMVC project from scratch

Currently, I am working on a project to implement PureMVC in TypeScript using npm and grunt. Unfortunately, PureMVC has ended development on their project and there is a lack of resources for PureMVC in TypeScript online. The documentation only provides in ...

Exploring the possibilities of updating carousel items in Angular using Bootstrap

I'm working on a project where I have 4 images and a carousel that needs to navigate to the respective index when one of the images is clicked. The challenge is that the carousel is built with Bootstrap and jQuery, but the rest of the application is A ...

Access the $event object from an Angular template selector

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script> <input type="file" #myFile multiple /> <button (click)="onDelete(myFile.event)">DeleteFiles</button> My code snippet is experienci ...

How does the type of the original array influence the inferred types of the destructured array values?

let arr = [7, "hello", true]; let [a, ...bc] = arr; typeof bc : (string | number | boolean)[] why bc type is (string | number | boolean) expect: because bc = ["hello", true], so bc type should be (string | boolean)[] ...

The parsing of a date string in JavaScript is done with the timezone of

let userInputDate = "2019-05-26" // received from browser query e.g. "d=1&date=2019-05-26" let parsedDate = new Date(userInputDate) console.log(JSON.stringify(parsedDate)) output: #=> "2019-05-25T19:00:00.0000Z" Issue When the user's time ...

What is the best way to store various types of functions within a single object key?

I have a dilemma where I am storing values and individual typed functions in an array of objects. Whenever I loop through the array, all the types of all typed functions in the array are required for any value. How can I make this more specific? Check it ...

Unresolved Axios jsonp request causing code blockage

Recently, I created a function to retrieve Google suggestions: const fetchGoogleSuggestions = async (searchQuery: string) => { const results = await axios({ url: `https://suggestqueries.google.com/complete/search?client=chrome&q=${searchQuery ...

Supabase Type Generation Not Working as Expected

Every time I try to update my typing through the cli command, I keep getting this error message without much information for me to troubleshoot. 2023/03/01 09:34:01 Recv First Byte Error: failed to retrieve generated types: {"message":"Forbi ...

What are some ways to get Angular2 up and running in a newly created distribution directory?

Trying to setup my own Angular2+Typescript (+SystemJS+Gulp4) starter project has hit a roadblock for me. I encountered issues when transitioning from compiling TypeScript in the same folder as JavaScript with access to the node_modules folder, to organizin ...

Only implement valueChanges on the second step of the form

I am utilizing the mat-stepper with a single form. My stepper has two steps only. I am looking to make an API request for every input value change, but only when the user is on the second step. How can I accomplish this? .ts ngOnInit() { this.formGr ...

Debugging is not possible for applications running on an Android device with Ionic 2

Instructions to replicate the issue: 1. Begin by creating a new project from the following repository: https://github.com/driftyco/ionic-starter-super 2. Execute the command `ionic run android` 3. Utilize chrome://inspect for debugging purposes The ...

The Angular 2 application is experiencing issues with displaying the Bootstrap 4.3 Modal

I am new to Angular so please forgive me if this question sounds silly. I am trying to implement a modal in my app and I followed an example from Bootstrap's documentation. However, the modal doesn't seem to work in my app. Everything else has be ...

Limitations on quantity utilizing typescript

Looking to create a type/interface with generics that has two properties: interface Response<T> { status: number; data: T | undefined; } Specifically, I want to enforce a rule where if the status is not equal to 200, then data must be undefined. ...

Explain a TypeScript function that takes an object as input and returns a new object with only the

Check Playground What's the best way to define a type for this specific function? The inputObject should contain all keys from the enablePropertiesArray and may have additional ones. The function is expected to return a copy of the inputObject, inclu ...

Angular 8 does not show the default option in the select tag

When I use the following code snippet: <div style="text-align:center"> <form> <select type="checkbox" name="vehicle1" (change)="onchange()" > <option> 1 </option> <opti ...

How can I target the initial last element within an *ngFor loop?

In my current project using Ionic, I am developing a personal application where I aim to implement an alphabetical header/divider for a list of games. The idea is to check the first letter of each game, and whenever it differs from the last game's ini ...

Generating Components Dynamically in Angular 4 Based on User-Defined Input

I am interested in developing an innovative App using Angular 4 that enables the creation of components from various storage sources such as database, URLs, and server-stored files. The main objective is to allow users to design their own components for pe ...

What could be causing TypeScript to throw errors when attempting to utilize refs in React?

Currently, I am utilizing the ref to implement animations on scroll. const foo = () => { if (!ref.current) return; const rect = ref.current.getBoundingClientRect(); setAnimClass( rect.top >= 0 && rect.bottom <= window.i ...