diff --git a/.changeset/thick-geckos-compete.md b/.changeset/thick-geckos-compete.md new file mode 100644 index 000000000..d3185de52 --- /dev/null +++ b/.changeset/thick-geckos-compete.md @@ -0,0 +1,5 @@ +--- +"openapi-typescript": patch +--- + +Fix: Correct handling of identical minItems and maxItems in array schemas when arrayLength option is true diff --git a/packages/openapi-typescript/src/transform/schema-object.ts b/packages/openapi-typescript/src/transform/schema-object.ts index 42f9dbd26..59c42b842 100644 --- a/packages/openapi-typescript/src/transform/schema-object.ts +++ b/packages/openapi-typescript/src/transform/schema-object.ts @@ -330,8 +330,14 @@ function transformSchemaObjectCore(schemaObject: SchemaObject, options: Transfor (min !== 0 || max !== undefined) && estimateCodeSize < 30 // "30" is an arbitrary number but roughly around when TS starts to struggle with tuple inference in practice ) { - // if maxItems is set, then return a union of all permutations of possible tuple types - if ((schemaObject.maxItems as number) > 0) { + if (min === max) { + const elements: ts.TypeNode[] = []; + for (let i = 0; i < min; i++) { + elements.push(itemType); + } + return tsUnion([ts.factory.createTupleTypeNode(elements)]); + } else if ((schemaObject.maxItems as number) > 0) { + // if maxItems is set, then return a union of all permutations of possible tuple types const members: ts.TypeNode[] = []; // populate 1 short of min … for (let i = 0; i <= (max ?? 0) - min; i++) { diff --git a/packages/openapi-typescript/test/transform/schema-object/array.test.ts b/packages/openapi-typescript/test/transform/schema-object/array.test.ts index e617df0b0..59a2fddb7 100644 --- a/packages/openapi-typescript/test/transform/schema-object/array.test.ts +++ b/packages/openapi-typescript/test/transform/schema-object/array.test.ts @@ -146,6 +146,20 @@ describe("transformSchemaObject > array", () => { }, }, ], + [ + "options > arrayLength: true > minItems: 2, maxItems: 2", + { + given: { type: "array", items: { type: "string" }, minItems: 2, maxItems: 2 }, + want: `[ + string, + string +]`, + options: { + ...DEFAULT_OPTIONS, + ctx: { ...DEFAULT_OPTIONS.ctx, arrayLength: true }, + }, + }, + ], [ "options > immutable: true", {