Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 20, 2025

Overview

This PR adds support for generating TypeScript non-empty array tuple types when an OpenAPI schema defines an array with a minItems constraint. This provides better type safety by ensuring arrays have at least the minimum required number of elements at compile time.

Problem

Previously, arrays with minItems constraints would generate standard Array<T> types, losing the valuable type information that the array must have at least N elements:

// Before: minItems constraint was ignored
nodeIds?: Array<number>;  // Could be empty despite minItems: 1
tags?: Array<string>;      // Could be empty despite minItems: 3

Solution

Arrays with minItems >= 1 and no maxItems (or maxItems != minItems) now generate tuple types with required elements followed by a rest element:

// After: minItems constraint generates non-empty tuple types
nodeIds?: [number, ...Array<number>];                    // minItems: 1
tags?: [string, string, string, ...Array<string>];       // minItems: 3
normalArray?: Array<number>;                              // no constraint

Type Generation Patterns

OpenAPI Schema Generated TypeScript Type
minItems: 0 Array<T>
minItems: 1 [T, ...Array<T>]
minItems: 3 [T, T, T, ...Array<T>]
minItems: 2, maxItems: 2 [T, T] (fixed-size, existing behavior)
minItems: 2, maxItems: 5 Array<T> (bounded arrays use regular type)
minItems: 101 Array<T> (exceeds safety limit of 100)

Implementation Details

Core Changes

  1. tsc/types.ts: Added createRestTypeNode helper to create TypeScript rest type nodes for tuple spread elements
  2. tsc/typedef.ts: Added createNonEmptyArrayTupleNode function that generates tuple types with required elements + rest element
  3. plugins/@hey-api/typescript/plugin.ts: Updated arrayTypeToIdentifier to check for minItems constraint and generate non-empty tuple types when appropriate
  4. utils/type.ts: Updated typeArray for backward compatibility with legacy parser

Safety Considerations

  • Safety limit: Only applies transformation for minItems <= 100 to avoid generating excessively long type definitions
  • Backward compatible: All existing tests pass, no breaking changes
  • Edge cases handled: Gracefully handles all combinations of minItems/maxItems

Testing

  • ✅ Added comprehensive test specification: specs/3.1.x/min-items-array.yaml
  • ✅ Added integration test with snapshot validation
  • ✅ All 910 existing unit tests passing
  • ✅ All 87 integration tests passing (including new minItems test)
  • ✅ TypeScript compilation and linting successful
  • ✅ Manual verification with edge cases

Example Usage

Given this OpenAPI specification:

parameters:
  - name: nodeIds
    in: query
    schema:
      type: array
      items:
        type: integer
      minItems: 1

The generated TypeScript type will now be:

query?: {
  nodeIds?: [number, ...Array<number>];
}

This provides compile-time safety ensuring the array has at least one element when provided.

Benefits

  • Type Safety: Catches potential bugs during development rather than at runtime
  • Better DX: IDEs provide better autocomplete and validation
  • Standards Compliant: Properly interprets OpenAPI/JSON Schema minItems constraint
  • Opt-in: Only affects schemas that explicitly define minItems, existing code unchanged

Fixes #[issue-number]

Original prompt

This section details on the original issue you should resolve

<issue_title>Add the possibility to generate non empty array types</issue_title>
<issue_description>### Description

We tried to generate a parameter type with a non empty array with "minItems": 1 json schema conf ( part of our openapi.json ) :

          {
            "name": "nodeIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer"
              },
              "title": "Contextual node ids",
              "examples": [
                [
                  1,
                  2,
                  3
                ]
              ],
              "minItems": 1,
              "default": []
            }
          },

We get this generated code in types.gen.ts :

/**
* Contextual node ids
*/
nodeIds: Array<number>;

But we would expect to generate something like :

/**
* Contextual node ids
*/
nodeIds: [number, ...number[]];

Here is opeanapi-ts.config.ts

import { defaultPlugins, defineConfig } from "@hey-api/openapi-ts";

export default defineConfig({
    input: "openapi.json",
    output: { format: "biome", path: "./src/client" },
    plugins: [
        ...defaultPlugins,
        "@hey-api/client-fetch",
        { name: "@hey-api/transformers", dates: true },
        { name: "@hey-api/sdk", transformer: true },
        {
            name: "@hey-api/typescript",
            readOnlyWriteOnlyBehavior: "off",
        },
    ],
});

And related comment to generate types.gen.ts

rm -rf ./src/client && openapi-ts -f ./openapi-ts.config.ts
```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

Fixes #2810


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@changeset-bot
Copy link

changeset-bot bot commented Oct 20, 2025

⚠️ No Changeset found

Latest commit: 90f6020

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Oct 20, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
hey-api-docs Ready Ready Preview Comment Oct 20, 2025 3:18pm

💡 Enable Vercel Agent with $100 free credit for automated AI reviews

@mrlubos
Copy link
Member

mrlubos commented Oct 20, 2025

@copilot there's already code for handling tuples, but I think it works only when both lower and upper bounds are defined. We'd be looking to make it work when only lower bounds are defined. This behavior should be automatic and we probably want to limit to something like minItems < 100, I think we already do something like this for tuples

Copilot AI changed the title [WIP] Add support for generating non empty array types Add support for non-empty array types with minItems constraint Oct 20, 2025
Copilot AI requested a review from mrlubos October 20, 2025 15:24
Copilot finished work on behalf of mrlubos October 20, 2025 15:24
Copilot finished work on behalf of mrlubos October 20, 2025 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add the possibility to generate non empty array types

2 participants