Skip to content

Commit da20fc9

Browse files
committed
Simplify minItems / maxItems tuple generation
Closes openapi-ts#2048
1 parent 713ea1b commit da20fc9

File tree

3 files changed

+34
-27
lines changed

3 files changed

+34
-27
lines changed

.changeset/clean-phones-deliver.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"openapi-typescript": patch
3+
---
4+
5+
Simplify minItems / maxItems tuple generation.

packages/openapi-typescript/src/transform/schema-object.ts

+13-27
Original file line numberDiff line numberDiff line change
@@ -339,40 +339,26 @@ function transformSchemaObjectCore(schemaObject: SchemaObject, options: Transfor
339339
typeof schemaObject.maxItems === "number" && schemaObject.maxItems >= 0 && min <= schemaObject.maxItems
340340
? schemaObject.maxItems
341341
: undefined;
342-
const estimateCodeSize = typeof max !== "number" ? min : (max * (max + 1) - min * (min - 1)) / 2;
342+
const estimateCodeSize = max === undefined ? min : (max * (max + 1) - min * (min - 1)) / 2;
343343
if (
344344
options.ctx.arrayLength &&
345345
(min !== 0 || max !== undefined) &&
346346
estimateCodeSize < 30 // "30" is an arbitrary number but roughly around when TS starts to struggle with tuple inference in practice
347347
) {
348-
if (min === max) {
349-
const elements: ts.TypeNode[] = [];
350-
for (let i = 0; i < min; i++) {
351-
elements.push(itemType);
352-
}
353-
return tsUnion([ts.factory.createTupleTypeNode(elements)]);
354-
} else if ((schemaObject.maxItems as number) > 0) {
355-
// if maxItems is set, then return a union of all permutations of possible tuple types
356-
const members: ts.TypeNode[] = [];
357-
// populate 1 short of min …
358-
for (let i = 0; i <= (max ?? 0) - min; i++) {
359-
const elements: ts.TypeNode[] = [];
360-
for (let j = min; j < i + min; j++) {
361-
elements.push(itemType);
362-
}
363-
members.push(ts.factory.createTupleTypeNode(elements));
364-
}
365-
return tsUnion(members);
366-
}
367348
// if maxItems not set, then return a simple tuple type the length of `min`
368-
else {
369-
const elements: ts.TypeNode[] = [];
370-
for (let i = 0; i < min; i++) {
371-
elements.push(itemType);
372-
}
373-
elements.push(ts.factory.createRestTypeNode(ts.factory.createArrayTypeNode(itemType)));
374-
return ts.factory.createTupleTypeNode(elements);
349+
if (max === undefined) {
350+
return ts.factory.createTupleTypeNode([
351+
...Array.from({ length: min }).map(() => itemType),
352+
ts.factory.createRestTypeNode(ts.factory.createArrayTypeNode(itemType)),
353+
]);
375354
}
355+
356+
// if maxItems is set, then return a union of all permutations of possible tuple types
357+
return tsUnion(
358+
Array.from({ length: max === undefined ? min : max - min + 1 }).map((_, index) =>
359+
ts.factory.createTupleTypeNode(Array.from({ length: index + min }).map(() => itemType)),
360+
),
361+
);
376362
}
377363

378364
const finalType =

packages/openapi-typescript/test/transform/schema-object/array.test.ts

+16
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,22 @@ describe("transformSchemaObject > array", () => {
128128
] | [
129129
string,
130130
string
131+
]`,
132+
options: {
133+
...DEFAULT_OPTIONS,
134+
ctx: { ...DEFAULT_OPTIONS.ctx, arrayLength: true },
135+
},
136+
},
137+
],
138+
[
139+
"options > arrayLength: true > minItems: 1, maxItems: 2",
140+
{
141+
given: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 2 },
142+
want: `[
143+
string
144+
] | [
145+
string,
146+
string
131147
]`,
132148
options: {
133149
...DEFAULT_OPTIONS,

0 commit comments

Comments
 (0)