[BUG][Typescript] Generated code with `oneOf` does not properly check the dto type
Bug Report Checklist
- [x] Have you provided a full/minimal spec to reproduce the issue?
- [x] Have you validated the input using an OpenAPI validator (example)?
- [x] Have you tested with the latest master to confirm the issue still exists?
- [ ] Have you searched for related issues/PRs?
- [x] What's the actual output vs expected output?
- [ ] [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
Given the OpenApi schema below, we have Dto with payload field, which has a type of oneOf of Payload1, Payload2 and Payload3. Each of payload types has a property type with type of enum with only one value.
When we generate client code, we get this code in models/DtoPayload.ts file:
export function DtoPayloadToJSON(value?: DtoPayload | null): any {
if (value == null) {
return value;
}
if (instanceOfPayload1(value)) {
return Payload1ToJSON(value as Payload1);
}
if (instanceOfPayload2(value)) {
return Payload2ToJSON(value as Payload2);
}
if (instanceOfPayload3(value)) {
return Payload3ToJSON(value as Payload3);
}
return {};
}
and code for each if check:
models/Payload1.ts
export function instanceOfPayload1(value: object): boolean {
if (!('type' in value)) return false;
if (!('barcode' in value)) return false;
return true;
}
models/Payload2.ts
export function instanceOfPayload2(value: object): boolean {
if (!('type' in value)) return false;
return true;
}
models/Payload3.ts
export function instanceOfPayload3(value: object): boolean {
if (!('type' in value)) return false;
if (!('barcode' in value)) return false;
return true;
}
since functions instanceOfPayload1 and instanceOfPayload3 are identical, generated code treats Payload3 as Payload1, which causes problems when converting plain objects to dto's.
openapi-generator version
7.5.0
OpenAPI declaration file content or url
{
"openapi": "3.0.0",
"paths": {
"/endpoint": {
"get": {
"operationId": "endpoint",
"summary": "endpoint",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Dto"
}
}
}
}
},
"security": [
{
"access-token": []
}
]
}
}
},
"info": {
"title": "API",
"description": "API",
"version": "1.0",
"contact": {},
"license": {
"name": "UNLICENSED",
"url": "UNLICENSED"
}
},
"tags": [],
"servers": [
],
"components": {
"securitySchemes": {
"access-token": {
"scheme": "bearer",
"bearerFormat": "JWT",
"type": "http",
"description": "JWT Authorization header using the Bearer scheme."
}
},
"schemas": {
"Payload3": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"AGE_VERIFICATION"
]
},
"barcode": {
"type": "string"
},
"requiredAge": {
"type": "number"
}
},
"required": [
"type",
"barcode"
]
},
"Payload2": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"ASSISTANCE_REQUESTED"
]
}
},
"required": [
"type"
]
},
"Payload1": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"PARTIAL_RESCAN"
]
},
"barcode": {
"type": "string"
}
},
"required": [
"type",
"barcode"
]
},
"Dto": {
"type": "object",
"properties": {
"payload": {
"description": "Payload for the assistance request",
"oneOf": [
{
"$ref": "#/components/schemas/Payload1"
},
{
"$ref": "#/components/schemas/Payload2"
},
{
"$ref": "#/components/schemas/Payload3"
}
]
}
},
"required": [
"payload"
]
}
}
}
}
Generation Details
npx -y @openapitools/openapi-generator-cli generate -g typescript-fetch
--additional-properties=importFileExtension=".js" --skip-validate-spec
-i ./test.json
-o src/api-client
Steps to reproduce
- make directory:
test - cd into directory
test - create file
test.jsonand copy and paste provided api schema above. - run provided in
Generation Detailscommand in cli
Related issues/PRs
Suggest a fix
We want the generator to also take into account types of fields, when checking if object is instance of another object.
for example:
export function instanceOfPayload1(value: object): boolean {
if (!('type' in value && value.type === Object.values(Payload1TypeEnum)[0])) return false;
if (!('barcode' in value)) return false;
return true;
}