diff --git a/src/index.test.ts b/src/index.test.ts index 110679d..0c203dc 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1074,6 +1074,33 @@ describe('generateTypeDeclaration()', () => { `); }); + test('should create tuples from min length arrays', async () => { + const schema: JSONSchema7 = { + title: 'FixedArrayToTupleTest', + type: 'object', + additionalProperties: false, + required: ['data'], + properties: { + data: { + type: 'array', + items: { type: 'string' }, + minItems: 2, + }, + }, + }; + + expect(toSource(await generateTypeDeclaration(context, schema))) + .toMatchInlineSnapshot(` +"export type FixedArrayToTupleTest = NonNullable<{ + data: NonNullable<[ + NonNullable, + NonNullable, + ...NonNullable[] + ]>; +}>;" +`); + }); + test('should work with tuples and rest test case schemas', async () => { const schema: JSONSchema7 = { title: 'TupleTest', diff --git a/src/index.ts b/src/index.ts index 4286344..4b5d13f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1312,6 +1312,31 @@ async function buildArrayTypeNode( ); } + // Switch from arrays to tuples and spread for small min length arrays + if ( + 'minItems' in schema && + typeof schema.minItems === 'number' && + schema.minItems > 0 && + schema.minItems < + context.jsonSchemaOptions.tuplesFromFixedArraysLengthLimit + ) { + return ts.factory.createTupleTypeNode( + new Array(schema.minItems) + .fill( + types.length > 1 ? ts.factory.createUnionTypeNode(types) : types[0], + ) + .concat( + ts.factory.createRestTypeNode( + ts.factory.createArrayTypeNode( + types.length > 1 + ? ts.factory.createUnionTypeNode(types) + : types[0], + ), + ), + ), + ); + } + return ts.factory.createArrayTypeNode( types.length > 1 ? ts.factory.createUnionTypeNode(types) : types[0], );