Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Excessively large type for maxItems #372

Closed
Nevon opened this issue Feb 26, 2021 · 6 comments
Closed

Excessively large type for maxItems #372

Nevon opened this issue Feb 26, 2021 · 6 comments

Comments

@Nevon
Copy link

Nevon commented Feb 26, 2021

Given a property such as:

{
  "type": "array",
  "minItems": 0,
  "maxItems": 1000,
  "items": {
    "type": "string",
    "anyOf": [
      {
        "$ref": "#/definitions/ipv4CidrBlockpattern"
      }
    ],
    "not": {
      "enum": [
        "0.0.0.0/0"
      ]
    }
  }
}

The generated type will be:

type ips = []
  | [Ipv4CidrBlockpattern & string]
  | [Ipv4CidrBlockpattern & string, Ipv4CidrBlockpattern & string]
  | [Ipv4CidrBlockpattern & string, Ipv4CidrBlockpattern & string, Ipv4CidrBlockpattern & string]
# ... and so on for each possible length of the array

Given a maxItems of 1000, the type definition becomes truly massive, and even fails to be generated in some cases.

Given a TupleOf type (from here) we could shrink this down quite a bit:

type BuildPowersOf2LengthArrays<N extends number, R extends never[][]> =
  R[0][N] extends never ? R : BuildPowersOf2LengthArrays<N, [[...R[0], ...R[0]], ...R]>;

type ConcatLargestUntilDone<N extends number, R extends never[][], B extends never[]> =
  B["length"] extends N ? B : [...R[0], ...B][N] extends never
    ? ConcatLargestUntilDone<N, R extends [R[0], ...infer U] ? U extends never[][] ? U : never : never, B>
    : ConcatLargestUntilDone<N, R extends [R[0], ...infer U] ? U extends never[][] ? U : never : never, [...R[0], ...B]>;

type Replace<R extends any[], T> = { [K in keyof R]: T }

type TupleOf<T, N extends number> = number extends N ? T[] : {
  [K in N]: 
  BuildPowersOf2LengthArrays<K, [[never]]> extends infer U ? U extends never[][]
  ? Replace<ConcatLargestUntilDone<K, U, []>, T> : never : never;
}[N];

type ips = Tuple<Ipv4CidrBlockpattern & string, 0>
  | TupleOf<Ipv4CidrBlockpattern & string, 1>
  | TupleOf<Ipv4CidrBlockpattern & string, 2>

This will still generate 1000 tuples in the union, but each tuple will only contain the parameter type once, rather than N times.

@panstromek
Copy link

We also have this problem for even smalller arrays but with more complex objects. Also, the generated type cannot be easily named/referenced and its items become distinct types. I'd prefer to just have the generated type be simple array and leave out the length completely, otherwise you get into the dependant type territory too much which just brings unnecessary amounts of coplexity, while it's not needed for most cases, because the length is runtime value anyway.

@Nevon
Copy link
Author

Nevon commented Feb 26, 2021

While it's not documented in the cli options, you can actually disable the min/maxlength check with the --ignoreMinAndMaxItems option. This is what we're doing now.

@panstromek
Copy link

That's good to know, thanks ;)

@bcherny
Copy link
Owner

bcherny commented Mar 28, 2021

ignoreMinAndMaxItems is documented in the README (https://github.com/bcherny/json-schema-to-typescript#options). Let's also document it in CLI options.

@bcherny
Copy link
Owner

bcherny commented May 22, 2022

Fixed in a89ffe1

1 similar comment
@bcherny
Copy link
Owner

bcherny commented May 22, 2022

Fixed in a89ffe1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants