diff --git a/src/internal/OpenApiTools/toTypeNode.ts b/src/internal/OpenApiTools/toTypeNode.ts index c4f92c2a..8bd5af8f 100644 --- a/src/internal/OpenApiTools/toTypeNode.ts +++ b/src/internal/OpenApiTools/toTypeNode.ts @@ -169,8 +169,8 @@ export const convert: Convert = ( return nullable(factory, typeNode, schema.nullable); } if (option && option.parent) { - Logger.info("Parent Schema:"); - Logger.info(JSON.stringify(option.parent)); + const message = ["Schema Type is not found and is converted to the type any. The parent Schema is as follows.", "", JSON.stringify(option.parent), ""].join("\n"); + Logger.info(message); } const typeNode = factory.TypeNode.create({ type: "any", @@ -253,6 +253,7 @@ export const convert: Convert = ( value: [], }); } + const value: ts.PropertySignature[] = Object.entries(schema.properties || {}).map(([name, jsonSchema]) => { return factory.PropertySignature.create({ name: converterContext.escapePropertySignatureName(name), @@ -268,6 +269,21 @@ export const convert: Convert = ( parent: schema.properties, }), }); + + const hasOptionalProperty = Object.keys(schema.properties || {}).some(key => !required.includes(key)); + if (hasOptionalProperty) { + const objectTypeNode = factory.TypeNode.create({ + type: schema.type, + value: value, + }); + const additionalObjectTypeNode = factory.TypeNode.create({ + type: schema.type, + value: [additionalProperties], + }); + return factory.IntersectionTypeNode.create({ + typeNodes: [objectTypeNode, additionalObjectTypeNode], + }); + } return factory.TypeNode.create({ type: schema.type, value: [...value, additionalProperties], diff --git a/test/__tests__/__snapshots__/typedef-only-test.ts.snap b/test/__tests__/__snapshots__/typedef-only-test.ts.snap index f4690cb4..3b0926c4 100644 --- a/test/__tests__/__snapshots__/typedef-only-test.ts.snap +++ b/test/__tests__/__snapshots__/typedef-only-test.ts.snap @@ -314,6 +314,14 @@ export namespace Schemas { } export type InferStringEnum = \\"a\\" | \\"b\\" | \\"c\\"; export type InferAnyNullable = null; + export interface OptionalPropertiesAndAdditionalProperties { + body?: { + key?: string; + description?: string; + } & { + [key: string]: string; + }; + } } " `; diff --git a/test/__tests__/__snapshots__/typedef-with-template-test.ts.snap b/test/__tests__/__snapshots__/typedef-with-template-test.ts.snap index 3d20d7b0..0397f261 100644 --- a/test/__tests__/__snapshots__/typedef-with-template-test.ts.snap +++ b/test/__tests__/__snapshots__/typedef-with-template-test.ts.snap @@ -1041,6 +1041,14 @@ export namespace Schemas { } export type InferStringEnum = \\"a\\" | \\"b\\" | \\"c\\"; export type InferAnyNullable = null; + export interface OptionalPropertiesAndAdditionalProperties { + body?: { + key?: string; + description?: string; + } & { + [key: string]: string; + }; + } } export type HttpMethod = \\"GET\\" | \\"PUT\\" | \\"POST\\" | \\"DELETE\\" | \\"OPTIONS\\" | \\"HEAD\\" | \\"PATCH\\" | \\"TRACE\\"; export interface ObjectLike { diff --git a/test/infer.domain/index.yml b/test/infer.domain/index.yml index d01837eb..b25b31b7 100644 --- a/test/infer.domain/index.yml +++ b/test/infer.domain/index.yml @@ -37,3 +37,15 @@ components: enum: [a, b, c] InferAnyNullable: nullable: true + OptionalPropertiesAndAdditionalProperties: + type: object + properties: + body: + type: object + properties: + key: + type: string + description: + type: string + additionalProperties: + type: string