@@ -310,72 +310,64 @@ function transformSchemaObjectCore(schemaObject: SchemaObject, options: Transfor
310310
311311 // type: array (with support for tuples)
312312 if ( schemaObject . type === "array" ) {
313- // default to `unknown[]`
314- let itemType : ts . TypeNode = UNKNOWN ;
315- // tuple type
316- if ( schemaObject . prefixItems || Array . isArray ( schemaObject . items ) ) {
317- const prefixItems = schemaObject . prefixItems ?? ( schemaObject . items as ( SchemaObject | ReferenceObject ) [ ] ) ;
318- itemType = ts . factory . createTupleTypeNode ( prefixItems . map ( ( item ) => transformSchemaObject ( item , options ) ) ) ;
319- }
320- // standard array type
321- else if ( schemaObject . items ) {
322- if ( hasKey ( schemaObject . items , "type" ) && schemaObject . items . type === "array" ) {
323- itemType = ts . factory . createArrayTypeNode ( transformSchemaObject ( schemaObject . items , options ) ) ;
324- } else {
325- itemType = transformSchemaObject ( schemaObject . items , options ) ;
313+ const arrayType = ( ( ) => {
314+ // tuple type
315+ if ( schemaObject . prefixItems || Array . isArray ( schemaObject . items ) ) {
316+ const prefixItems = schemaObject . prefixItems ?? ( schemaObject . items as ( SchemaObject | ReferenceObject ) [ ] ) ;
317+ return ts . factory . createTupleTypeNode ( prefixItems . map ( ( item ) => transformSchemaObject ( item , options ) ) ) ;
326318 }
327- }
328319
329- const min : number =
330- typeof schemaObject . minItems === "number" && schemaObject . minItems >= 0 ? schemaObject . minItems : 0 ;
331- const max : number | undefined =
332- typeof schemaObject . maxItems === "number" && schemaObject . maxItems >= 0 && min <= schemaObject . maxItems
333- ? schemaObject . maxItems
334- : undefined ;
335- const estimateCodeSize = typeof max !== "number" ? min : ( max * ( max + 1 ) - min * ( min - 1 ) ) / 2 ;
336- if (
337- options . ctx . arrayLength &&
338- ( min !== 0 || max !== undefined ) &&
339- estimateCodeSize < 30 // "30" is an arbitrary number but roughly around when TS starts to struggle with tuple inference in practice
340- ) {
341- if ( min === max ) {
342- const elements : ts . TypeNode [ ] = [ ] ;
343- for ( let i = 0 ; i < min ; i ++ ) {
344- elements . push ( itemType ) ;
345- }
346- return tsUnion ( [ ts . factory . createTupleTypeNode ( elements ) ] ) ;
347- } else if ( ( schemaObject . maxItems as number ) > 0 ) {
348- // if maxItems is set, then return a union of all permutations of possible tuple types
349- const members : ts . TypeNode [ ] = [ ] ;
350- // populate 1 short of min …
351- for ( let i = 0 ; i <= ( max ?? 0 ) - min ; i ++ ) {
320+ // standard array type
321+ const itemType : ts . TypeNode = schemaObject . items ? transformSchemaObject ( schemaObject . items , options ) : UNKNOWN ;
322+
323+ const min : number =
324+ typeof schemaObject . minItems === "number" && schemaObject . minItems >= 0 ? schemaObject . minItems : 0 ;
325+ const max : number | undefined =
326+ typeof schemaObject . maxItems === "number" && schemaObject . maxItems >= 0 && min <= schemaObject . maxItems
327+ ? schemaObject . maxItems
328+ : undefined ;
329+ const estimateCodeSize = typeof max !== "number" ? min : ( max * ( max + 1 ) - min * ( min - 1 ) ) / 2 ;
330+ if (
331+ options . ctx . arrayLength &&
332+ ( min !== 0 || max !== undefined ) &&
333+ estimateCodeSize < 30 // "30" is an arbitrary number but roughly around when TS starts to struggle with tuple inference in practice
334+ ) {
335+ if ( min === max ) {
352336 const elements : ts . TypeNode [ ] = [ ] ;
353- for ( let j = min ; j < i + min ; j ++ ) {
337+ for ( let i = 0 ; i < min ; i ++ ) {
354338 elements . push ( itemType ) ;
355339 }
356- members . push ( ts . factory . createTupleTypeNode ( elements ) ) ;
340+ return tsUnion ( [ ts . factory . createTupleTypeNode ( elements ) ] ) ;
341+ } else if ( ( schemaObject . maxItems as number ) > 0 ) {
342+ // if maxItems is set, then return a union of all permutations of possible tuple types
343+ const members : ts . TypeNode [ ] = [ ] ;
344+ // populate 1 short of min …
345+ for ( let i = 0 ; i <= ( max ?? 0 ) - min ; i ++ ) {
346+ const elements : ts . TypeNode [ ] = [ ] ;
347+ for ( let j = min ; j < i + min ; j ++ ) {
348+ elements . push ( itemType ) ;
349+ }
350+ members . push ( ts . factory . createTupleTypeNode ( elements ) ) ;
351+ }
352+ return tsUnion ( members ) ;
357353 }
358- return tsUnion ( members ) ;
359- }
360- // if maxItems not set, then return a simple tuple type the length of `min`
361- else {
362- const elements : ts . TypeNode [ ] = [ ] ;
363- for ( let i = 0 ; i < min ; i ++ ) {
364- elements . push ( itemType ) ;
354+ // if maxItems not set, then return a simple tuple type the length of `min`
355+ else {
356+ const elements : ts . TypeNode [ ] = [ ] ;
357+ for ( let i = 0 ; i < min ; i ++ ) {
358+ elements . push ( itemType ) ;
359+ }
360+ elements . push ( ts . factory . createRestTypeNode ( ts . factory . createArrayTypeNode ( itemType ) ) ) ;
361+ return ts . factory . createTupleTypeNode ( elements ) ;
365362 }
366- elements . push ( ts . factory . createRestTypeNode ( ts . factory . createArrayTypeNode ( itemType ) ) ) ;
367- return ts . factory . createTupleTypeNode ( elements ) ;
368363 }
369- }
370364
371- const finalType =
372- ts . isTupleTypeNode ( itemType ) || ts . isArrayTypeNode ( itemType )
373- ? itemType
374- : ts . factory . createArrayTypeNode ( itemType ) ; // wrap itemType in array type, but only if not a tuple or array already
365+ return ts . factory . createArrayTypeNode ( itemType ) ;
366+ } ) ( ) ;
375367
376368 return options . ctx . immutable
377- ? ts . factory . createTypeOperatorNode ( ts . SyntaxKind . ReadonlyKeyword , finalType )
378- : finalType ;
369+ ? ts . factory . createTypeOperatorNode ( ts . SyntaxKind . ReadonlyKeyword , arrayType )
370+ : arrayType ;
379371 }
380372
381373 // polymorphic, or 3.1 nullable
0 commit comments