openapi2aspida icon indicating copy to clipboard operation
openapi2aspida copied to clipboard

`anyof` keyword is not converted appropreately

Open bigen1925 opened this issue 3 years ago • 4 comments

Description

OpenAPI schema

"SchemaX": {
  "anyOf" : [SchemaA, SchemaB]
}

is converted to

type SchemaX = Partial<SchemaA & SchemaB>

, but I think it shoud be converted to

type SchemaX = SchemaA | SchemaB

.

Maybe its source code is arround https://github.com/aspida/openapi2aspida/blob/main/src/builderUtils/props2String.ts#L37-L40 .

Environment

  • Package version: v0.19.0
  • OS:
    • [x] Linux
    • [ ] Windows
    • [ ] macOS
  • Node.js version: v18.2.0
  • npm version: 8.9.0

Additional context

Thanks for developing this awesome library!

bigen1925 avatar Jul 01 '22 00:07 bigen1925

From the description on this site, it seems that the implementation of anyOf is incomplete but not wrong.

https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/

solufa avatar Jul 02 '22 11:07 solufa

For the example of the page, schemas of PetByAge and PetByType are represented in Typescript as

type PetByAge = {
  age: number
  nickname?: string
}

type PetByType = {
  pet_type: 'Cat' | 'Dog'
  hunts?: boolean
}

, and considering two types below,

type SchemaX = Partial<PetByAge & PetByType>
type SchemaY = PetByAge | PetByType

I think a union type represents more precisely the schema as documented.

Because the schema of anyof PetByAge and PetByType should reject

{
  "nickname": "Mr. Paws",
  "hunts": false
}

, but SchemaX accepts it and SchemaY reject.

const x: SchemaX = {"nickname": "Mr. Paws",  "hunts": false}  // assignable :(
const y: SchemaY = {"nickname": "Mr. Paws",  "hunts": false}  // error, not assignable :)

And also Schema Y accepts all objects that the schema accepts

const y: SchemaY = { "age": 1 }
const y: SchemaY = { "pet_type": "Cat", "hunts": true }
const y: SchemaY = { "nickname": "Fido", "pet_type": "Dog", "age": 4}

bigen1925 avatar Jul 02 '22 14:07 bigen1925

And I found other wrong case.

Considering the case below,

components:
  schemas:
    schemaA:
      type: object
      properties: 
        id: 
          type: integer
      required:
        - id
          
    schemaB:
      type: object
      properties:
        id:
          type: string
      required: 
        - id
    
    schemaX:
      anyof:
        - $ref: '#/components/schemas/schemaA'
        - $ref: '#/components/schemas/schemaB'

schemaA and schemaB will be converted to

type SchemaA = { id: number }

type SchemaB = { id: string }

and schemaX should accept { id: string } or { id: number }.

However, schemaX is converted to

type SchemaX = Partial<schemaA & schemaB>
// = {id?: undefined}

with current implementation because schemaA & schemaB is { id: never }.

On the otherhand, if with union type implementation, SchemaX will be converted to

type SchemaX = SchemaA | SchemaB
// = {id: string | integer}

.

bigen1925 avatar Jul 06 '22 06:07 bigen1925

@solufa Is there any chance this feature request will be accepted?

If needed, I am able to create PR.

bigen1925 avatar Aug 30 '22 08:08 bigen1925

Fixed in v0.23.0

solufa avatar Aug 05 '23 11:08 solufa